How to display fix banner between QMenubar and QToolBar in QMainWindow - qt

How can I show fixed banner (with some widget like label and button ) in between
QMenuBar and QToolBar ?
Similarly like QStatusBar but in between QMenuBar and QToolBar.
I tried to implement using QToolBar.
// toolbar Banner with lable inside it.
QLabel * bannerLabel = new QLabel(" bannerToobar with label banner.");
bannerLabel->setAlignment( Qt::AlignVCenter );
ui.bannerToobar->addWidget( bannerLabel );
ui.bannerToobar->setAllowedAreas(Qt::ToolBarArea::TopToolBarArea);
ui.bannerToobar->setMovable( false );
QSize banner_sz = ui.bannerToobar->size();
ui.bannerToobar->setFixedHeight( banner_sz.height() * 2 );
QSizePolicy banner_szPolicy( QSizePolicy::Policy::Maximum, QSizePolicy::Policy::Fixed );
banner_szPolicy.setHorizontalStretch(255);
ui.bannerToobar->setSizePolicy( banner_szPolicy );
but i can't prevent user from draging mainToolbar and droping in the same row as my
bannerToolbar

You can force it to wrap initially using QMainWindow::addToolBarBreak, but I don't know a way to prevent it from being put back there later by the user (except for making the toolbars non-moveable).
If there was a QToolbar::dockLocationChanged signal (which seems to have been requsted and resolved in https://bugreports.qt-project.org/browse/QTBUG-1274, but I still don't see the signal anywhere), I suppose you could use insertToolBarBreak to fix it up whenever things have changed. Maybe there's some hackish way you could get notified when the toolbars move.
Or you could use QMainWindow::setMenuWidget to place a widget containing both your QMenuBar and something else into the menu area of the QMainWindow. This could get tricky if you want to support styles (mac/gnome/etc) where the menubar gets lifted out of your window to the top-of-screen and the toolbar gets unified with the window title decorations. But the idea of a banner between menubar and toolbar just naturally has problems in such cases :-)

Related

Qt: Map a clicked signal to another button

I wanted to have a collapsible widget. I used this code: How to make an expandable/collapsable section widget in QT.
I wanted the title of the QToolButton to be on the far left and the triangle icon to be on the right. I deleted the title, and moved the icon. Then I created a QPushButton and made it look like a QLabel and positioned it where I wanted the title to be. Now, I would like the title to be clickable - to have the same effect as clicking on the toggle icon would have. How do I connect these two signals?
Code for the QToolButton:
QObject::connect(toggleButton, &QToolButton::clicked, [this](const bool checked)
{
toggleButton->setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::UpArrow);
toggleAnimation->setDirection(checked ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
toggleAnimation->start();
});
You can also write it like this:
QObject::connect(titleLabel, &QPushButten::clicked, toggleButton, &QToolButton::clicked);
I found that this works:
QObject::connect(titleLabel, &QPushButton::clicked, [this]
{
toggleButton->click();
});
Disclaimer: I have no idea if that is the correct way to do this.

How to set animated icon to QPushButton in Qt5?

QPushButton can have icon, but I need to set animated icon to it. How to do this?
I created new class implemented from QPushButton but how to replace icon from QIcon to QMovie?
This can be accomplished without subclassing QPushButton by simply using the signal / slot mechanism of Qt. Connect the frameChanged signal of QMovie to a custom slot in the class that contains this QPushButton. This function will apply the current frame of the QMovie as the icon of the QPushButton. It should look something like this:
// member function that catches the frameChanged signal of the QMovie
void MyWidget::setButtonIcon(int frame)
{
myPushButton->setIcon(QIcon(myMovie->currentPixmap()));
}
And when allocating your QMovie and QPushButton members ...
myPushButton = new QPushButton();
myMovie = new QMovie("someAnimation.gif");
connect(myMovie,SIGNAL(frameChanged(int)),this,SLOT(setButtonIcon(int)));
// if movie doesn't loop forever, force it to.
if (myMovie->loopCount() != -1)
connect(myMovie,SIGNAL(finished()),myMovie,SLOT(start()));
myMovie->start();
Since I had to solve this problem for a project of mine today, I just wanted to drop the solution I found for future people, because this question has lots of views and I considered the solution quite elegant. The solution was posted here. It sets the icon of the pushButton every time, the frame of the QMovie changes:
auto movie = new QMovie(this);
movie->setFileName(":/sample.gif");
connect(movie, &QMovie::frameChanged, [=]{
pushButton->setIcon(movie->currentPixmap());
});
movie->start();
This also has the advantage, that the icon will not appear, until the QMovie was started. Here is also the python solution, I derived for my project:
#'hide' the icon on the pushButton
pushButton.setIcon(QIcon())
animated_spinner = QtGui.QMovie(":/icons/images/loader.gif")
animated_spinner.frameChanged.connect(updateSpinnerAniamation)
def updateSpinnerAniamation(self):
#'hide' the text of the button
pushButton.setText("")
pushButton.setIcon(QtGui.QIcon(animated_spinner.currentPixmap()))
Once you want to show the spinner, just start the QMovie:
animated_spinner.start()
If the spinner should disappear again, then stop the animation and 'hide' the spinner again. Once the animation is stopped, the frameChanged slot won't update the button anymore.
animated_spinner.stop()
pushButton.setIcon(QtGui.QIcon())

Need to display the widgets inside my QListWidget with an offset, basically shifted a bit to the right

I have a panel.ui file done using QTDesigner. It's a QFrame class, rectangular shape with few labels on it. And I have a QListWidget class where I insert 3 instances of the panel.ui.
I create a QListWidgetItem and then use List->SetItemWidget(..) to populate my list.
The Result is a list filled with three panels. I was also able to move the panels inside the list using dragDropMode internalMove.
I also tested the ability to shift the panels a bit to the right when I click on them and that worked:
in procedure List::mousePressEvent(QMouseEvent *event)
Panel *child = static_cast<Panel*>(childAt(event->pos()))
...
int y= child->pos().y();
int x = child->pos().x();
child->move (x +10, y); `
Problem: When I run the app and display the list, I want all the panels to be displayed with that 10 offset to the right. So in the List constructor and inside the loop after this->setItemWidget(myPanelItem, myPanel); I try using myPanel->move() like above but it doesn't seem to work.
I run the app, the panels are displayed without my offset ( not sure why?) but when I click on one, it shifts.
move() won't work reliably since the widgets are in a layout. (Well, not a layout as in a QLayout, but the effect is comparable: When any metric in your application changes, e.g. you resize or scroll the list, the widgets are repositioned by the list widget.)
What you can do is wrap your actual widget in a container widget with a layout margin:
QWidget* wrapIntoContainerForOffset(QWidget* widget, int offset /*in pixels*/) {
QWidget* container = new QWidget;
QHBoxLayout* layout = new QLayout(container);
layout->setContentsMargins(/*left=*/ offset, /*others=*/ 0, 0, 0);
layout->addWidget(widget);
return container;
}
Then you add these containers to the listwidget instead.
Have You tried StyleSheets. The QListWidget supports Box model( http://doc.qt.digia.com/qt/stylesheet-customizing.html#box-model ). So You may want to try playing around with margins in the stylesheets.
Style sheet reference: http://doc.qt.digia.com/qt/stylesheet-reference.html

fixing child layout/widget position in QT

I wanted to know whether is there any way of fixing child layouts within a parent layout. For example...
QVBoxLayout *vbox = new QVBoxLayout;
// adding pushbuttons/layouts...
vbox->addWidget(one);
vbox->addWidget(two);
vbox->addWidget(three);
vbox->addWidget(four);
Now this ends up as four buttons/layouts in a vertical layout in the sequence that they are added. But if I remove buttons/layouts "one", "two" and "three"...
vbox->removeWidget(one);
vbox->removeWidget(two);
vbox->removeWidget(three);
After doing this, the pushbutton "four" will move up the layout as you remove widgets on top of "four". I don't want this to happen.
Is there any way that even if I remove the widget/layout on top, I need that last widget/layout to stay where it is currently.
How do I achieve this ?
UPDATE: Well I was experimenting and I was kind of able to achieve what I wanted using QGridLayout. Here is the code, but I am using QGridLayout instead of QVBoxLayout.
connect(one,SIGNAL(clicked()),this,SLOT(remove_btns()));
g = new QGridLayout(this);
g->addWidget(one,0,0,1,2);
g->addWidget(two,1,0,1,2);
g->addWidget(three,2,0,1,2);
g->addWidget(four,3,0,1,2,Qt::AlignBottom);
setLayout(g);
If I delete the above three buttons, the fourth one stays where it is, because of QT::AlignBottom , it does not work without that thing.
Here is the SLOT remove_btns()
void test::remove_btns()
{
g->removeWidget(one);
g->removeWidget(two);
g->removeWidget(three);
delete one;
delete two;
delete three;
}
When I click "one", top three buttons vanish, and the fourth one stays where it is. But it does not work if I don't give the QT::AlignBottom . Also, these alignment things are a mystery to me, I am unable to find how exactly they work.
This is definitely NOT an answer..., because I don't understand how it worked :P
If you are immediately replacing the widgets you removed, you can always insert your new widgets by index.
void insertWidget ( int index, QWidget * widget, int stretch = 0, Qt::Alignment alignment = 0 )
Yes, just hide the widgets instead of removing them:
one->hide();
two->hide();
three->hide();
If you really have to remove the widgets, perhaps you can replace them with some lightweight widget like a QLabel with no text.

how to add an widget into the Form In QtDesigner

in qdesigner_workbench.cpp, how can I add a widget (say QLabel) into a FormWindow by code?
Since methods like createWidget()...etc are all abstract, how do I properly use the internal mechanics to add QLabel into the active FormWindow?
EDIT:
In qdesigner_workbench.cpp, this is currently what I have:
QDesignerFormWindowManagerInterface* fwm = core()->formWindowManager();
QDesignerFormWindowInterface* fw = fwm->activeFormWindow();
QWidget* mw = fw->mainContainer();
QLabel* label = new QLabel(mw); //can be added correctly but not in the right hierarchy
label->setText("I am a good girl.");
The mw (obtained from fw->mainContainer()) is actually a MainWindow, however the real data I need is in:
mw -> children[2] (which is a QDesignerWidget) -> children
There are 9 widgets in the designer, and you can see there's 9 arrays in children mentioned above; see this link (an image) for illustration.
http://img24.imagevenue.com/img.php?image=98871_a_122_476lo.jpg
So... how can I correctly add the QLabel widget?
Tried both
QLabel* label = new QLabel(fw); // will be a sibling of MainContainer, which is the QMainWindow (mw) in this case
QLabel* label = new QLabel(mw); // will be a sibling of QDesignerWidget
and apprarently either of the works.
If you want just to display a widget on a form, you can set your QMainWindow or QDialog to be the widget parent:
QLabel *l = new QLabel(this);
l->setText("My long string");
Where this is a pointer pointing to your current QDialog or QMainWindow.
Otherwise as ufukgun pointed out, you can use setCentralWidget if you need your widget to occupy the center of the QMainWindow.
You should add any QWidget to the QLayout of the form.This will put it into the display strategy of the form when resizing it.
form->ui->layout->add(yourQWidget);
Depending of the QLayout you are using, parameters of the add function will not be the same.
create a widget and add it to your main window as it is your central widget
mainWindow->setCentralWidget(centralWidget);
if you want to add a label, you can add it to this central widget

Resources