Detect when NSWindow's "Show Tab Bar" gets enabled - nswindow

I have a height-limited window: It cannot grow above a certain height (based on its current content), but can be made smaller (in which case I'll add a vertical scrollbar).
I limit the maximum height with a NSLayoutConstraint.
Now, if the user enables tabbed windowing by checking the menu command View -> Show Tab Bar, the window's contents get moved down in order to make room for the tab bar but the entire window's height remains the same, which effectively leads to the content being "squished", so that my current code decides to add the vertical scrollbar, as if the user just reduced the window height manually.
I rather have the window grow with the bar tab instead. How can I accomplish this?
There seems to be no event or notification that would inform me when the Tab Bar got enabled.
What's a clean way to detect the activation of the Tab Bar then, so that I can grow my window height along with it?

I poked around with KVO and found that I could watch NSWindow's tabbedWindows property for this purpose (tested on 10.13.6).
In the ViewController's viewWillAppear:
if ([self.view.window respondsToSelector:#selector(tabbedWindows)]) {
[self.view.window addObserver:self forKeyPath:#"tabbedWindows" options:0 context:nil];
}
And then handle the change:
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(id)change context:(void*)context {
// ... adjust my window's height
}
This may not be reliable, though, i.e. I found no documentation that guarantees that this will work in the future and is not just an accidental side effect.

Related

Getting QScrollArea to resize its child widget immediately

I have a QScrollArea (we'll call it myContainer) that contains and scrolls a child view (we'll call it myChildWidget). All works almost fine - when I change the height of myChildWidget dynamically in response to something, if the height exceeds that of myContainer (the QScrollArea), a vertical scroll bar pops into view, effectively narrowing myChildWidget since I've set it to resize its child using:
myContainer->setWidgetResizable(true);
The problem is that myChildWidget is not actually resized until later, rather than right when I set its new height or try resizing myContainer, so I can't do certain things depending on its new width without subclassing and putting in a whole bunch of extra code. Surely there's something I can call to get the QScrollArea to auto-resize its child right away, right? I can use:
QCoreApplication::processEvents();
but the problem with that is that it causes the widgets to flash and redraw when I'm not done setting things up. I've tried update(), updateGeometry(), and adjustSize(), both on the container and its child, and none work. Anything I'm missing? Thanks for any help.

Resize QDialog at a runtime

I have a QDialog subclass containing some options of my application. Some of the options are core, the other are advanced, so I decided to put them into separeted checkable QGroupBox.
I want my dialog to shrink verticaly when the user checked off advanced options box, but I can't find the way to do it properly - the dialog size stays exactle the same
I set dialog's size policy to Expanding, tried to call adjustSize() and tried to call resize() method - nothing helps. I can't resize programmaticaly dialog to be smaller then it's current size (it only can become larger). At the same time, it is possible to resize it manualy.
Can anybody help me?
If you don't need manual resize, you can add
layout()->setSizeConstraint(QLayout::SetFixedSize);
to the dialog constructor, then the layout takes over the responsibility to automatically resize when widgets are shown or hidden.

React when a scrollbar activates

I have a TextInput in a container. I need the horizontal scrolling capabilities of the container so that when the textInput is to big it allows me to scroll to see the text on the left and right. The scrollbar track and thumb were set to null so I can see the text.
trackSkin: ClassReference(null);
thumbUpSkin: ClassReference(null);
thumbOverSkin: ClassReference(null);
thumbDownSkin: ClassReference(null);
thumbSkin: ClassReference(null);
Now I want to listen to an event or watch a property that changes when the horizontal scrollbar activates. Then I would like to set a padding on the container or left and right property on the text input so that the left and right arrows do not get in the way of the user to see the first and last characters.
Thanks
Before adding listeners and accessing the HScrollBar of the Scroller, you may find this setting/variable of some use: measuredSizeIncludesScrollBars
From the API: (Please forgive the terrible formatting)
If true, the Scroller's measured size includes the space required for the visible scroll bars, otherwise the Scroller's measured size depends only on its viewport.
Components like TextArea, which "reflow" their contents to fit the available width or height may use this property to stabilize their measured size. By default a TextArea's is defined by its widthInChars and heightInChars properties and in many applications it's preferable for the measured size to remain constant, event when scroll bars are displayed by the TextArea skin's Scroller.
In components where the content does not reflow, like a typical List's items, the default behavior is preferable because it makes it less likely that the component's content will be obscured by a scroll bar.
In the event this doesn't work, I would probably add an event listener attached to the lifecycle of the Scroller. During that event handling, I would check to see if the Scrollbar was null or not. If it wasn't, I would store it off to the side, but not before adding a listener to its "show" and "hide" event. That way, you can kick off whatever you need to whenever the scrollbar changes its state.

Qt: When is layout "Final"?

I'm having a problem where I cannot deterministically tell when a layout takes place.
Simplified example:
I have a widget with two sub-widgets.
Top widget has expanding width and fixed height. Let's say the fixed height defaults to 50.
Bottom widget has expanding height and width
There's a vertical layout set up.
Let's say there's a button somewhere i can click to run code. The button is not on the widget itself to make things simple...
When the button is clicked, i do the following:
I measure the height of the bottom expandable widget. The height is 100.
I then "topWidget->SetMaximumHeight(100)", and "topWidget->SetMinimumHeight(100)"
I measure the height of the bottom expandable widget again. The height is still 100
But I see the bottom expandable widget change height!
this means that when I do step #3, the layout hasn't taken place yet. No matter what I do, update(), updateGeometry() - I cannot get the bottom widget to change height between step #2 and step #3.
The only way for me to resolve this is to have a timer wait, say 250ms, and then measure the height of the bottom widget -- and then It's always correct - meaning the re-layout took place correctly
This is a crazy/dirty solution, but I don't have another. Is there an API I am missing to allow me to deterministically, synchronously change the layout and query for the new size of affected widgets right after?
from user: alexisdm
Try calling QApplication::processEvents() between steps #2 and #3 (it should do what the timer allow the event loop to do)

Getting rid of unnecessary scrollbar in QScrollArea

I'm working on a Configuration QDialog. It has several categories (General, Appearance, etc.) that get loaded when the user clicks on them. Each category has its own page. These pages are separate classes in their own right (each has its own ui, cpp, and h). When the Preferences window loads, the pages get instantiated and are loaded into a QStackedWidget. The Stackedwidget is then placed into a QScrollArea so it can scroll if necessary.
However, there is a problem. Ever since I added the QStackedWidget, the QScrollArea always has a vertical scrollbar even when the current page is short enough not to need one: (picture shows the shortest page)
The ScrollArea vertical scroll policy is set to Qt::ScrollBarAsNeeded so logically it should only show a bar if the page is larger than the viewable area.
Here's what I already tried to fix this:
Setting the scroll policy to Qt::ScrollBarAlwaysOff. While this gets rid of the scrollbar, its unacceptable since it doesn't let the user know they need to scroll on long pages.
Setting the Minimum/Maximum heights for the QStackedwidget. This makes the scrollbar go away if I set it for a low enough value, but it is unacceptable since it causes some of the widgets to have a squished appearance.
I know the problem has something to do with the QStackedWidget but since this is the first time I've used QStackedWidget I’m not sure what it is. I've also noticed the scroll is always for the same amount; i.e. the scrollable area is always the same size no matter how large/small the page widget is. For some reason, it's slightly larger than the longest page. At first I thought the vertical spacers I put at at the bottom of each page to tighten up the layout were causing this, but taking them out didn't fix it.
Update: Here's the code that controls the Stackedwidget:
void Newconfig::on_Categories_currentItemChanged(QTreeWidgetItem *current)
{
QModelIndex index=ui->Categories->currentIndex();
int idx=index.row();
QString category=current->text(0);
this->setWindowTitle("Preferences -- " + category);
if (stack->currentWidget() != 0) {
stack->currentWidget()->setSizePolicy(QSizePolicy::Ignored,
QSizePolicy::Ignored);
}
stack->setCurrentIndex(idx);
stack->currentWidget()->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
adjustSize();
}
The QStackedWidget takes the size of the largest widget added to it. In your case, the largest page in your preferences dialog is what is influencing the size of the QStackedWidget and is thus forcing the scroll area to show its scroll bar, even when it doesn't appear to be necessary.
To get around this, you can create a slot that is triggered right before you change the current widget in the QStackedWidget that sets the size policy of the page you are leaving to QSizePolicy::Ignored and the size policy of the page you are about to show to whatever you desire for that page -- QSizePolicy::Expanding for instance. An example of this technique is detailed on this page. There's a lot of code in the example, but the important part is here:
void changeCurrent(int idx)
{
if (stackWidget->currentWidget() !=0) {
stackWidget->currentWidget()->setSizePolicy(QSizePolicy::Ignored,
QSizePolicy::Ignored);
}
stackWidget->setCurrentIndex(idx);
stackWidget->currentWidget()->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
adjustSize();
}
This function is called to change the current index on the QStackedWidget. It causes the page that was just being viewed to have a size policy that has no influence on the overall size of the QStackedWidget and the page that is about to be viewed to have a size policy of consequence.

Resources