changing size of Widget from QStyle - qt

I am writting a QStyle Here I am changing the QProgressBar to a Slim single line, no text. So Height will also be reduced to 5px. However Widget Width will be determined by layout. what should I do in My Style's drawControl to change widget height ?

I've never actually written a QStyle but I would consider it odd if you were supposed to resize anything inside drawControl. I could be wrong on this by a quick review of the documentation would seem to suggest that you would override subElementRect and return a rect based on current width and your preferred height. I assume this would be called by layout activities and would be sorted out by the time drawControl gets called.

Do you need the height for the widget to be fixed? Or just the drawn height to never go past 5 pixels? For the first, set the height and resize policy on the polish function. For the second, override the drawing in the QStyle to only use 5 pixels. The functions that do the drawing generally take rects; you can call the base class's draw with a modified rect if you properly override the appropriate functions. Unfortunately, it's been years since I've done any QStyle work, so I'm not sure exactly what those functions are.

Related

How can I set a QPushButton to grow vertically?

Background: I need Command Link-like controls. Normally, I would use Qt's builtin QCommandLinkButton, but in this case I need to also support Right-to-Left layouts. Regrettably, QCommandLinkButton doesn't seem to respect Qt::RightToLeft when set explicitly via setLayoutDirection. There also doesn't seem to be a way to override the layout direction via style sheets.
I tried to work around this issue by using QPushButton: I instantiated QPushButton and replaced its contents with a custom layout containing two labels stacked vertically. This did not work because QPushButton refused to expand horizontally.
Failing to make QPushButton instances work, I decided to try sub-classing it. No matter what I tried (overriding sizeHint, setting vertical sizePolicy to expanding, resizeing explicitly, etc) the button refuses to grow more than 30 pixels high.
If I change QPushButton to QWidget, the new widget grows normally.
The question: How can I force a QPushButton to grow vertically and fit its inner widgets? If this is not possible, what are my options for a button-like widget that is both visually and behaviorally consistent with QPushButton and other "native" controls?
I managed to get the button to grow normally by setting the maximum height to 16777214 (instead of the default 16777215), and then setting the content margins of the button to 10.
Perplexingly, the default maximum height of a QPushButton should be plenty, but for some reason it refuses to grow past 30 pixels unless the maximum height is explicitly set to something else.
Place the button inside a layout and set its vertical size policy to Maximum.

QSizePolicy true meaning, documentation and thoughts

I have been now two years working deeply with Qt layout system. After this time i encountered thosand of problems with SizePolicies and Layouts. I normally found out solutions, but never really understood what i was doing.
Now i was taking some time to try to understand correctly and build a 101 GUIDE for them and never fail. I found out this piece of information in the documentation about QSizePolicy of a QWidget:
This property holds the default layout behavior of the widget
If there is a QLayout that manages this widget's children, the size
policy specified by that layout is used. If there is no such QLayout,
the result of this function is used.
I thought that if you had a QLabel, for example, and you set the policies to Horizontal Expanding, Vertical Fixed, THE LABEL itself changed that way.
But it doesn't, at all.
When reading that i see that it talks about ITS CHILDREN inside the LAYOUT. So what does it mean, then?. Nothing is inside the label, is that why it does not work?.
WHat about inserting a label inside a QFrame, and telling the frame to be Expanding... Will the QFrame expand or stretch (depending on the rest of brother widgets in the same Layout) or will the label expand or stretch, not the QFrame?
What a mess...
What about Stretching?. If you set stretching 10 when you add the widget:
layout->addwidget(label, 10, Qt::AlignHCenter);
It doesn't work either.
Stretch 0 when you add the widget means : Take the policies i told you. Default, depends on the type of widget. Button-like widgets have expanding-fixed. Box-like Expanding-Expanding...
Stretch 10 means: grow maximum.
Am i right? Well. When having a QFrame and a QLabel inside, setting Expanding, and 10 to strech to the label DOES NOT WORK.
I don't understand all of your questions, so I will only answer to those that I think i do.
I thought that if you had a QLabel, for example, and you set the policies to Horizontal Expanding, Vertical Fixed, THE LABEL itself
changed that way. But it doesn't, at all.
I don't know what that means. What is the exact behavior you're expecting and what is actually happening? Is this label in a layout? Are there any other widgets in this layout?
WHat about inserting a label inside a QFrame, and telling the frame to be Expanding...
If you set a QSizePolicy to your QFrame object and set a layout to it, this size policy might be ignored. Docs: If there is a QLayout that manages this widget's children, the size policy specified by that layout is used. If there is no such QLayout, the result of this function is used. This means that the widget's layout should manage the size of the widget. Note that it will still respect the minimum/maximum width/height values.
Stretch 10 means: grow maximum.
What makes you think that?. The stretch factor is dependent on other widgets inside the layout. Docs: Stretch factors are used to change how much space widgets are given in proportion to one another.
When having a QFrame and a QLabel inside, setting Expanding, and 10 to strech to the label DOES NOT WORK.
Does not work how? If you set stretch for QFrame to 1 and for QLabel to 10, your QLabel object should always be 10 times as wide/high(depending of your layout type) as your QFrame object. If your QFrame has a layout and it contains children, then this might not work as it would depend on the childrens size policies.

Displaying an image and automatically re-size it

I can't quite figure out what the best way of displaying an image is in my particular case, so hopefully someone on here has a few tips.
I want to display an image that gets re-sized automatically to fit inside the space that is available. I currently do this by creating a class derived from QLabel that implements void resizeEvent(QResizeEvent*) where I do a QPixmap::scaled to re-size the image. The problem is that this only works when the widget is enlarged because the widget doesn't get a resizeEvent when I try to make the widget smaller. I guess that because I set the image to the same size as the widget, it isn't allowed to be sized smaller again? I guess I could try to create a smaller image therefor introducing a sort of "border" around the image which would perhaps allow re-size events to occur when making the area smaller. Any thoughts?
resizeEvent is sent whenever size is changed. It doesn't matter whether it is enlarged or not.
But you can set Policy and Max/Min size to constraint widget in shrinking/enlarging. So if you have your widget not getting resizeEvent AND it doesn't shrink either, then look at your size policy and min width/height. If it shrinks but you doesn't have resizeEvent then you have some error in you logic, I believe.
Alternatively you can use paintEvent for image painting and use QWidget::rect() for your widget width/height.
Try changing the size policy of the label to QSizePolicy::Preferred.
Have a look at size policies in general.

Resizing QT's QTextEdit to Match Text Height: maximumViewportSize()

I am trying to use a QTextEdit widget inside of a form containing several QT widgets. The form itself sits inside a QScrollArea that is the central widget for a window. My intent is that any necessary scrolling will take place in the main QScrollArea (rather than inside any widgets), and any widgets inside will automatically resize their height to hold their contents.
I have tried to implement the automatic resizing of height with a QTextEdit, but have run into an odd issue. I created a sub-class of QTextEdit and reimplemented sizeHint() like this:
QSize OperationEditor::sizeHint() const {
QSize sizehint = QTextBrowser::sizeHint();
sizehint.setHeight(this->fitted_height);
return sizehint;
}
this->fitted_height is kept up-to-date via this slot that is wired to the QTextEdit's "contentsChanged()" signal:
void OperationEditor::fitHeightToDocument() {
this->document()->setTextWidth(this->viewport()->width());
QSize document_size(this->document()->size().toSize());
this->fitted_height = document_size.height();
this->updateGeometry();
}
The size policy of the QTextEdit sub-class is:
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
I took this approach after reading this post.
Here is my problem:
As the QTextEdit gradually resizes to fill the window, it stops getting larger and starts scrolling within the QTextEdit, no matter what height is returned from sizeHint(). If I initially have sizeHint() return some large constant number, then the QTextEdit is very big and is contained nicely within the outer QScrollArea, as one would expect. However, if sizeHint gradually adjusts the size of the QTextEdit rather than just making it really big to start, then it tops out when it fills the current window and starts scrolling instead of growing.
I have traced this problem to be that, no matter what my sizeHint() returns, it will never resize the QTextEdit larger than the value returned from maximumViewportSize(), which is inherited from QAbstractScrollArea. Note that this is not the same number as viewport()->maximumSize(). I am unable to figure out how to set that value.
Looking at QT's source code, maximumViewportSize() is returning "the size of the viewport as if the scroll bars had no valid scrolling range." This value is basically computed as the current size of the widget minus (2 * frameWidth + margins) plus any scrollbar widths/heights. This does not make a lot of sense to me, and it's not clear to me why that number would be used anywhere in a way that supercede's the sub-class's sizeHint() implementation. Also, it does seem odd that the single "frameWidth" integer is used in computing both the width and the height.
Can anyone please shed some light on this? I suspect that my poor understanding of QT's layout engine is to blame here.
Edit: after initially posting this, I had the idea to reimplement maximumViewportSize() to return the same thing as sizeHint(). Unfortunately, this did not work as I still have the same problem.
I have solved this issue. There were 2 things that I had to do to get it to work:
Walk up the widget hierarchy and make sure all the size policies made sense to ensure that if any child widget wanted to be big/small, then the parent widget would want to be the same thing.
This is the main source of the fix. It turns out that since the QTextEdit is inside a QFrame that is the main widget in a QScrollArea, the QScrollArea has a constraint that it will not resize the internal widget unless the "widgetResizable" property is true. The documentation for that is here: http://doc.qt.io/qt-4.8/qscrollarea.html#widgetResizable-prop. The documentation was not clear to me until I played around with this setting and got it to work. From the docs, it seems that this property only deals with times where the main scroll area wants to resize a widget (i.e. from parent to child). It actually means that if the main widget in the scroll area wants to ever resize (i.e. child to parent), then this setting has to be set to true.
So, the moral of the story is that the QTextEdit code was correct in overriding sizeHint, but the QScrollArea was ignoring the value returned from the main frame's sizeHint.
Yay! It Works!
You may try setting minimumSize property of the QTextEdit to see if that force the layout to grow.
I don't understand most of Qt's layout scheme but setting minimum and maximum size pretty much does what I want it to do. Well, most of the time anyways.

Qt QHboxLayout cell size ssues

For those of you who haven't been reading my Qt questoins, I am learning Qt for a project. I have only limited experience with GUI design at all, and not in Qt.
I've got a horizontal layout that I want to populate with some buttons. I can feed these buttons in just fine, but my formerly-square buttons are stretched horizontally to take up more space.
I want to let the layout manager determine the best way to size these buttons, but I also want their original proportions to remain intact. For instance, if I start would with 32X32 buttons that need to shrink to fit all of them in the layout, I want them to shrink proportionally so that the width to height scale is maintained. 20X20, 16X16, 12X12 would all be just fine, but 24X16 would be an example of dimensions that are unacceptable.
I've tinkered with size policies on the buttons and stretch options. I'm not seeing, even after reading the QPushButton and QHboxLayout classes how to do this. How is it accomplished?
Thanks.
As long as I understand the question correctly, I think what you want is QBoxLayout::addStretch(). This will add a spacer object that fills the unused space. So the buttons will have their ideal size and the spacer will fill the rest. You can try experimenting with this in Designer, it's easier than the write/compile/run cycle.
You should take a look at the answers to this question. This is a recap of my answer there.
You need to create a custom derivative of QLayoutItem, which overrides bool hasHeightForWidth() and int heightForWidth( int width ) to preserve the aspect ratio. You could either pass the button in and query it, or you could just set the ratio directly. You'll also need to make sure the widget() function returns a pointer to the proper button.
Once that is done, you can add a layout item to a layout in the same manner you would a widget. So when your button gets added, change it to use your custom layout item class.
I haven't actually tested any of this, so it is a theoretical solution at this point. I don't know of any way to do this solution through designer, if that was desired.

Resources