Resizing qt widgets when their children are hidden - qt

How would I go about resizing the widget when the retry child is hidden so that it looks as in the first image? The main layout is a QVBoxLayout, the retry child is a widget with a QVBoxLayout as well.
I've tried the following:
update()
updateGeometry()
setGeometry(childrenRect())
layout()->activate()
on the main widget as soon as I've set the retry widget to hidden. Do I need to intercept some event to do this?

The adjustSize function may do what you want.

Here is a basic example which does auto-resize upon widget hide/show.
dialog.h file:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtGui>
class dialog : public QDialog
{
Q_OBJECT
public:
explicit dialog(QWidget *parent = 0)
{
vlayout.addWidget(&checkbox);
vlayout.addWidget(&label);
label.setText("Label");
setLayout(&vlayout);
this->layout()->setSizeConstraint(QLayout::SetFixedSize); // !!! This is the what makes it auto-resize
checkbox.setChecked(true);
connect(&checkbox,SIGNAL(toggled(bool)),&label,SLOT(setVisible(bool)));
}
private:
QVBoxLayout vlayout;
QCheckBox checkbox;
QLabel label;
};
#endif // DIALOG_H
and main.c
#include <QApplication>
#include "dialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
dialog d;
d.show();
return a.exec();
}

My problem was a little different in that I had a top-level QWidget (instead of a QDialog or a QMainWindow) that had children within a layout. When those children were resizing to larger, the QWidget would resize to accommodate, but not when they became SMALLER. Much like above, the area just had empty space. I finally found a solution:
The layout used in my QWidget had a property called setSizeConstraint(). This is normally set to "QLayout::SetDefaultConstraint", which simply affects the "minimumSize" of the QWidget that owns it. Instead, I chose "QLayout::SetFixedSize" which made the layout adjust the fixed size of the owning QWidget, effectively making it SMALLER when it needed to be.

This is one I have just developed an answer for!!! ( Note: this will be given in PyQt4 form )
I have needed the ability to re-size my app window when showing and hiding extra panels.
However in the past I ended up just reconfiguring the UI and/or work flow so that re-sizing the window wasn't necessary. However now it is a needed must.
The window can be re-sized during its creation. The window can be re-sized directly (e.g. self.resize( xSize, ySize )
However if you create some lines of code that capture the needed sizes, hides the desired section, recalculates what the size should be, the re-size seems to be not take at all.
(example)
curHgt = self.size().height()
curWth = self.size().width()
myFrmHgt = self.ui.reviewFrm.size().height()
self.ui.reviewFrm.hide()
self.resize( curWth, (curHgt - myFrmHgt ) )
Nothing. Doesn't work. Why not?
It today's hunt for an answer still did not come up with a viable answer. There are several offerings for options. Hunt up the widget hierarchy, invalidate, adjustSize. A rather exhaustive layout shaking that just will not work if you are attempting to re-size the the main window. There was also an overwhelming response of saying to set your constraint to FixedSize. But that rather defeats the entire purpose, kinda like saying to cut your hand off at the wrist if you have a hang nail.
However I did stumble across someone that had some success with digging in and discovering that the reason the re-size isn't taking hold is because of the queue of Posted Events that will reset the resize.
His solution was to run the QApplication.sendPostedEvents() just before doing your application re-size, so that the queued events don't reset your window.
Yes, and No.
Yes, this is the solution, and I am sure there is a prettier way of doing it, but you need to really shake the the queue out like a washed paint roller first.
Here is my simple snippet that I set up that so far seems to be solid.
result = [ self.size().width(), self.size().height() ]
if self.ui.reviewFrm.isVisible():
result[1] -= self.ui.reviewFrm.size().height()
self.ui.reviewFrm.hide()
while self.size().height() > result[1]:
self.appy.sendPostedEvents()
self.resize( result[0], result[1] )
Nope. It ain't pretty. However at most I have only seen it shake the paint roller twice before the Posted Events allowed for the window to resize.
No need to lock constraints or shake the parent widgets or climb through the hierarchy looking for size hints.

If you want your widget to be resizable after setting QLayout::SetFixedSize you will also need to override QWidget::resizeEvent().
void resizeEvent(QResizeEvent* event) override {
QWidget::resizeEvent(event);
layout()->setSizeConstraint(QLayout::SetMinAndMaxSize);
};

Related

Qt QStackedWidget Resizing Issue

I have a simple QStackedWidget with 3 different QWidgets in it. The minimum sizes of the QWidgets are (350x200), (200x100), and (450x450).
So the problem I'm having is when I resize the QStackedWidget, it has a minimum size of the largest QWidget within it. So if I switch to the second QWidget, (which is the QWidget with the size of (200x100)), the QStackedWidget will only size down (450x450) because of the largest QWidget inside of it. I would like it to size down to fit the current QWidget being displayed, and remove that minimum size.
I think that the most straightforward solution is to subclass QStackedWidget and override sizeHint and minimumSizeHint to return the hint for the current widget instead of the maximum of all widgets. For example:
class StackedWidget : public QStackedWidget
{
QSize sizeHint() const override
{
return currentWidget()->sizeHint();
}
QSize minimumSizeHint() const override
{
return currentWidget()->minimumSizeHint();
}
};
Good question. Unfortunately Qt doesnt provide automatic mechanisms for sizing down depending on child widgets (By automatic I mean you don't have to do anything). Most of the focus is on expanding (see the size policies)
You have two options :
Use the signal and slots mechanism in the class which create those widgets. You will need to listen to the signal void QStackedWidget ::currentChanged ( int index ) and resize the stackedwidget to the size of the widget at index. This is quite fast to code.
Decorate QStackedWidget and define the size properties. Basically both sizeHint() and minimumSizeHint() should return the size of the current widget. Addwidget(QWidget*) also need to be modified. Useful if you are using stacked widgets everywhere.
step 1: overload method:
void resizeEvent(QResizeEvent*)
step 2: call 'resize' and 'select page' :
QRect rect;
rect.setBottomRight(stackedWidget->geometry().bottomRight());
currentWidget->setGeometry(rect);
An alternate solution is to not use stacked widget at all and instead make one Widget for each page and then use the setVisible(bool) to show and hide the pages. That way you get the resizing behavior without having to make custom widgets.

How do you create cool "mirror" effect for items displayed in a graphical GUI?

I have a QGraphicsScene and I add a couple of QGraphicsItem(s) to the scene. All the items being added to the scene are QGraphicsPixmapItem.
I want the output displayed scene to have a "mirror" visual effect for each item that is added to the scene. I would like the "mirror" visual effect to look a little something to the iTunes mirror affect when you display albums:
(NOTE: Image seen above is from "CoverFlow company website". CoverFlow are the people that I think implemented the iTunes album display "mirror" visual effect.)
Notice how each item in this scene has a mirror below it.
How do you create this "mirror" visual effect (seen in the screenshot) for each item?
I suppose this is how I would do it. I guess this is good for you as well according to the comment.
I would simply create the reflected mirrored image from the original using the QPainter and merge the two (using the QPainter again). This resulting image is the one shown using the QGraphicsPixmapItem. In the code below I created the reflected mirrored version of the image. All you need to do then is to tune the parameters and merge.
#include <QApplication>
#include <QLabel>
#include <QPixmap>
#include <QPainter>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Just to show the original image.
QLabel label;
QImage original(<place_an_image_path_here>);
label.setPixmap(QPixmap::fromImage(original));
label.show();
// Create the gradient that will be placed over the image.
QPoint start(0, 0);
QPoint end(0, original.height());
QLinearGradient gradient(start, end);
gradient.setColorAt(0.0, Qt::white);
gradient.setColorAt(0.5, Qt::black);
// Create the mask to be used on the mirrored image.
QImage mask(original.size(), original.format());
QPainter painter(&mask);
// You may want to add additional opacity according
// to the sample image shown.
painter.setOpacity(0.8);
painter.fillRect(original.rect(), gradient);
painter.end();
// Create the mirrored reflection.
QImage reflection = original.mirrored();
reflection.setAlphaChannel(mask);
// Just to show the result.
QLabel labelReflection;
labelReflection.setPixmap(QPixmap::fromImage(reflection));
labelReflection.show();
return a.exec();
}
You can load the resulting image (the result of the merge of the two) in a QGraphicsPixmapItem and then you can go on applying all the transformations you need.
EDIT: I forgot that you may also want to set an additional opacity, as the image provided seems to do. I didn't try, but it might be possible to do the same using QPixmaps. This should improve performance or even allow, depending on the platform and on the paint engine you're using, accelerated painting.
EDIT2: As requested this is the output of my test code:
(I hope this image is not under some copyright or similar, I tried to check but nothing was written)

Qt Stylesheet. Background-color, YES. background-image, NO

It's a weird problem with stylesheets: I have a window, child of class QWidget. I apply a stylesheet to it to ideally change the background of the entire window to an image with a repeat-x and repeat-y, tiling it.
The stylesheet "pipeline" works. If I use "background-color" and set it to say, red, the entire window will be painted red. however, if I use the background-image, it does not. if i add a CHILD WIDGET (using Qt-Designer) inside the window, the background-image will work, just inside that child widget, but not outside of it, all over the parent window.
Obviously I am doing something wrong, but am really clueless as to why the background-color would work on the entire window, but the background-image won't, unless there's a child widget, and then, only inside of it.
I had a similar problem and it was solved by reading Qt Stylesheets docs.
As it is said in the Qt's stylesheets reference, applying CSS styles to custom widgets inherited from QWidget requires reimplementing paintEvent() in that way:
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
Without doing it your custom widgets will support only the background, background-clip and background-origin properties.
You can read about it here: Qt Stylesheets reference in the section "List of Stylable Widgets" -> QWidget.
Hope, it will help!
I know this is kind of an old question, but I stumbled across it because I was having the exact same problem.
It turns out if you create your widget as a subclass of QFrame instead of a QWidget, the background-image property seems to take fine. Also , as Dave's example shows, if you just create a "raw" QWidget, it also seems to work fine. For whatever reason, if you create a new widget derived from QWidget, background-image no longer works.
If you create your widgets in Qt Designer or Creator, they don't have an option to create a QFrame-derived widget, so I just tell it I want a QWidget-derived class, then manually change the .cpp and .h file to derive from QFrame instead of QWidget.
The code below is working fine on my machine. Maybe you can see where it differs from what you have? Hope it is helpful.
#include <QtGui>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget main_window;
main_window.setStyleSheet("background-image: url(Chrysanthemum.jpg); "
"background-position: top left; "
"background-repeat: repeat-xy;");
main_window.show();
return app.exec();
}

Turn off opaque resizing of QMainWindow / QDockWidget separator

Is it possible to turn off opaque resizing on QMainWindow / QDockWidget separators?
(i.e. the central widget only resizes once the separator is dropped, and not during the drag.)
QMainWindow has an animated property that specifies whether animation is used for manipulation of dock widgets and tool bars. By default, this property is enabled so you'll get dynamic (and animated) resizing of the central widget when moving dock widgets around. Clearing it should give you functionality similar to turning off opaque resize in a QSplitter.
QMainWindow* mainWin(new QMainWindow);
mainWin->setAnimated(false);
Maybe you could subclass QSlider and override sliderChange(SliderChange change) and not invoce the superclass method as long as the slider is still being dragged? That is assuming that this is the correct method that will eventually emit the signals that update the guy around. Haven't tested it, but thats generally a pattern that works in QT (for instance one can subclass the reject slot of QDialgo to abort dialogs).

QT4: Is it possible to make a QListView scroll smoothly?

I have a QListView in Icon mode with lots of icons, so that a scrollbar appears, but the scrolling is not smooth and this IMHO confuses the user since it jumps abruptly from one point to another at each scroll. I would like to make the scrolling smooth but I didn't find anything in the docs. Is it possible?
Maybe QListView.setVerticalScrollMode(QAbstractItemView::ScrollPerPixel)
If I understand your question correctly you would like to redefine the scrolling behavior of the widget. I guess what happens is that listview is getting scrolled by the item's height whenever users hits a scroll arrow (marked as b on the image below).
For a vertical scroll bar connected to a list view, scroll arrows typically move the current position one "line" up or down, and adjust the position of the slider by a small amount. I believe line in this case it is an icon's height. You can adjust items height by installing and item delegate (setItemDelegate) and overriding its sizeHint method. Though this would not help you to solve this problem. What you could try is to create a QListView descendant and override its updateGeometries method. There you can setup the vertical scrollbar step to the value you want, I guess 1 or 2 for this task. Below is an example of the custom listview:
class TestListView : public QListView
{
Q_OBJECT
public:
explicit TestListView(QWidget *parent = 0);
protected:
virtual void updateGeometries();
};
TestListView::TestListView(QWidget *parent) :
QListView(parent)
{
//???
}
void TestListView::updateGeometries()
{
QListView::updateGeometries();
verticalScrollBar()->setSingleStep(2);
}
hope this helps, regards
I have a QlistWidget* in ui->barra_scroll and I feel very smooth with this.
QScrollBar *qsb = ui->barra_scroll->verticalScrollBar();
qsb->setSingleStep(5);

Resources