Hi, I have a problem with changing window title and central widget in Qt.
There is MainWindow:
class MainWindow : public QMainWindow
{
// (...)
QStackedWidget* widgets;
Quiz* widget1, *widget2;
}
and there is a class Quiz:
class Quiz : public QWidget
{
public slots:
void myClicked();
}
I wanted to change MainWindow title after clicking on button, which is a element of Quiz (and it is connected with slot myClicked).
void Quiz::myClicked()
{
static_cast<MainWindow>(parent).myFunction();
}
void MainWindow::myFunction()
{
widget2 = new Quiz(this,2);
widgets->addWidget(widget2);
std::cout<<"current wdgt: " << widgets->currentIndex() << std::endl; // shows: 0
widgets->setCurrentWidget(widget2);
std::cout<<"current wdgt " << widgets->currentIndex() << std::endl; // shows: 1
setWindowTitle("newTitle");
std::cout<<"Title is " << windowTitle().toStdString() << std::endl;
}
So widgets->currentIndex shows index of new widget but nothing is changed in my window. The same problem is with window title - method windowTitle() returns new title, but title on a titlebar is old. Why?
If I change title in Quiz::myClicked by:
parent->setWindowTitle("newTitle");
it works! Why it works how strange? Please help.
it works! Why it works how strange? Please help.
It is not strange. That is how the Qt API is designed. See the documentation for the explanation:
windowTitle : QString
This property holds the window title (caption).
This property only makes sense for top-level widgets, such as windows and dialogs.
Let us analyze the last sentence: your quiz is neither a QMainWindow, nor a QDialog, hence it cannot work. Windows titles only make sense for those based on the documentation. When you call it on the parent, it will work respectively since that is a QMainWindow.
The title bar shows the title of the MainWindow. Your Quiz widgets are "inside" the MainWindow, so their titles are not shown.
If you want to change the title bar text, you must call MainWindow::setWindowTitle().
Related
I have a simple QWidget in a QDockWidget and my own title bar for this dock widget. In this title bar, I put a QPushButton that, when triggered, will allow me to:
set the title bar vertical
hide the widget inside the QDockWidget
I managed to get both of them working separately, but I can't succeed in doing it simultaneously.
Here is the code for the title bar:
QDockTitleBar::QDockTitleBar(const QString &title, QDockWidget * parent)
: QWidget(parent)
{
pDock = qobject_cast<QSuiteDockWidget*>(parentWidget());
m_pMainLayout = new QHBoxLayout(this);
m_pLabel = new QLabel(title, this);
m_pMainLayout->addWidget(m_pLabel);
m_pMainLayout->addStretch();
m_pToggleButton = new QPushButton(this);
//m_pToggleButton->setIcon(...); // whatever
m_pToggleButton->setFlat(true);
connect(m_pToggleButton, SIGNAL(clicked()), this, SLOT(toggleButtonTriggered()));
m_pMainLayout->addWidget(m_pToggleButton);
}
void QDockTitleBar::resizeEvent(QResizeEvent* event)
{
if (pDock->features() & QDockWidget::DockWidgetVerticalTitleBar)
qDebug() << "I am Vertical";
else
qDebug() << "I am Horizontal";
}
void QDockTitleBar::toggleButtonTriggered()
{
const QDockWidget::DockWidgetFeatures features = pDock->features();
if(features & QDockWidget::DockWidgetVerticalTitleBar)
{
pDock->widget()->show(); // comment this one...
pDock->setFeatures(features ^ QDockWidget::DockWidgetVerticalTitleBar);
}
else
{
pDock->widget()->hide(); //... and this one : the title bar is set vertical
pDock->setFeatures(features | QDockWidget::DockWidgetVerticalTitleBar);
}
}
In my main function :
QDockWidget* dock = new QDockWidget();
dock->setWindowTitle("DOCK");
QDockTitleBar* labelDock = new QDockTitleBar("DOCK", dock);
QWidget* widget = new QWidget(dock);
dock->setTitleBarWidget(labelDock);
dock->setWidget(widget);
addDockWidget(Qt::RightDockWidgetArea, dock);
NB : If I change pDock->widget()->hide() in pDock->widget()->show() and vice versa, I almost have the desired behavior, but the widget is hidden when the title bar is horizontal (I want it to be hidden when the title bar is vertical)...
I also put the resizeEvent(). When I trigger the button, title bar horizontal, I have :
I am Vertical
I am Horizontal
I am Horizontal
and if I trigger the button once again :
I am Vertical
I am Horizontal
I am Horizontal
I am Horizontal
Can anyone explain me this behavior and/or tell me what am I doing wrong and how I can fix it?
Edit : I work on Qt5.6, if that matters.
I am not focusing on the resizeEvent() being called or not, it's just the behavior that is not the one wanted. At the moment :
1/ If I use this code :
if(features & QDockWidget::DockWidgetVerticalTitleBar)
pDock->setFeatures(features ^ QDockWidget::DockWidgetVerticalTitleBar);
else
pDock->setFeatures(features | QDockWidget::DockWidgetVerticalTitleBar);
It works like it is supposed to work : the title bar is set vertical when the button is triggered, and back to horizontal when I trigger the button again. Plus, the widget is always shown.
2/ If I use this code :
if(features & QDockWidget::DockWidgetVerticalTitleBar)
{
pDock->widget()->show();
pDock->setFeatures(features ^ QDockWidget::DockWidgetVerticalTitleBar);
}
else
{
pDock->widget()->hide();
pDock->setFeatures(features | QDockWidget::DockWidgetVerticalTitleBar);
}
Then, if I trigger the button, the widget is hidden (as wanted), BUT the title bar is not set vertical. If I trigger the button again, the widget is shown (as wanted), and the title bar is still horizontal (seems normal, since it didn't change at the first triggering).
3/ If I use this code (this is where the behavior seems to be near of what I want) :
if(features & QDockWidget::DockWidgetVerticalTitleBar)
{
pDock->widget()->hide();
pDock->setFeatures(features ^ QDockWidget::DockWidgetVerticalTitleBar);
}
else
{
pDock->widget()->show();
pDock->setFeatures(features | QDockWidget::DockWidgetVerticalTitleBar);
}
Then :
first triggering : title bar set vertical (it is OK) BUT widget still shown
second triggering : title bar back to horizontal BUT widget hidden this time
third triggering, and after : title bar vertical with widget shown, then title bar horizontal with widget hidden. I would like the opposite, i.e. title bar vertical/widget hidden and title bar horizontal/widget shown.
First of all I tried to compile your example with qt4.86 and qt5.5.1. And they behave a little bit different. With qt4.86 I think it works fine. But with qt5.5.1 it really shows "I am Horizontal" as you described. I don't know why they differ, but they do.
By the way it works on both qt4.86 and qt5.5.1 when I deattach QDockWidget from mainwindow.
So I think it works in the way you don't expect because you think that, when you hide your widget, QDockTitleBar::resizeEvent will be certainly called. But it is not always true. For example if the width of your hiding widget is not very big and so the width of your dockwidget is determined by the titlebar width, then resizeEvent in qt5.5.1 will not be called. If you want your QDockTitleBar::resizeEvent to be always called after showing/hiding of your widget you can explicitly call QCoreApplication::sendEvent ( QObject * receiver, QEvent * event ) with QResizeEvent instance.
You may try to remove and then reassign your widget from the QDockWidget instead of hiding it.
if(features & QDockWidget::DockWidgetVerticalTitleBar)
{
pDock->setFeatures(features ^ QDockWidget::DockWidgetVerticalTitleBar);
pDock->setWidget(pDockWidget);
}
else
{
pDock->setFeatures(features | QDockWidget::DockWidgetVerticalTitleBar);
pDockWidget = pDock->widget();
pDock->setWidget(0);
}
I have a GUI project in Qt Creator that functions as a shopping list. I am using a QLineEdit to add items to a QTableWidget. The user types something in, presses the QPushButton. The slot then adds a new row to the QTableWidget with the input, in the first column, and a new QPushButton in the second column. I then want the user to be able to press the button and have it clear that row, but I don't know how to access that slot, or sender (I'm not sure the proper term.) Here is the code so far. itemList is my QTableWidget, itemInput is the QLineEdit.
void MainWindow::on_btnAddItem_clicked()
{
ui->itemList->insertRow(ui->itemList->rowCount());
ui->itemList->setItem((ui->itemList->rowCount())-1,0,new QTableWidgetItem(ui->itemInput->text()));
QPushButton *clear = new QPushButton("Clear",this);
ui->itemList->setIndexWidget(ui->itemList->model()->index(ui->itemList->rowCount()-1, 1), clear);
ui->itemInput->clear();
}
Here is when the program is initially run. Once they click the button, it runs on_btnAddItem_clicked()
Then it looks like this, and I want to make the clear button remove the row it is a part of.
Do I need to create a new slot? Any help?
You will need to make your own button class and inherit QPushButton. Something like this :
class MyButton : public QPushButton {
public:
MyButton();
QTableWidgetItem *titem;
}
And here you MainWindow :
void MainWindow::on_btnAddItem_clicked()
{
ui->itemList->insertRow(ui->itemList->rowCount());
ui->itemList->setItem((ui->itemList->rowCount())-1,0,new QTableWidgetItem(ui->itemInput->text()));
MyButton *clear = new MyButton("Clear",this);
clear->titem = ui->itemList->item(ui->itemList->rowCount()-1, 0);
connect(clear, SIGNAL(clicked()), SLOT(on_btnClear_Clicked()));
ui->itemList->setIndexWidget(ui->itemList->model()->index(ui->itemList->rowCount()-1, 1), clear);
ui->itemInput->clear();
}
void MainWindow::on_btnClear_Clicked()
{
MyButton *btn = (MyButton*)QObject::sender();
ui->itemList->removeRow(btn->titem->row());
}
Please note, it is only step to do it.
I have a QListWidget in my MainWindow that displays a list of VideoWidgets (a custom QWidget).
VideoWidget has a clickable label where on clicking the label it should delete a file and then remove the QListItem which holds the VideoWidget from the QListWidget. Here is my VideoWidget class:
VideoWidget::VideoWidget(QWidget *parent) : QWidget(parent)
{
ClickableLabel *smallRed = new ClickableLabel(this)
//...
QObject::connect(smallRed,SIGNAL(clicked()),this,SLOT(removeVideo()));
}
void VideoWidget::removeVideo(){
//...code to remove a file
QListWidget* list = myParent->getList();
QListWidgetItem* item = list->takeItem(list->currentIndex().row());
myList->removeItemWidget(item);
}
The problem is that clicking the smallRed label will not select its item in the QListWidget which means that list->currentIndex().row() will return -1. Clicking anywhere else in the Widget does select the current item. For the code to work I currently have to first click anywhere in the VideoWidget and then click its ClickableLabel. Is there any way I can achieve the same effect with one single click on my ClickableLabel?
From your previous qestion, we suggested use signal and slots. For example:
for(int r=0;r<3;r++)
{
QListWidgetItem* lwi = new QListWidgetItem;
ui->listWidget->addItem(lwi);
QCheckBox *check = new QCheckBox(QString("checkBox%1").arg(r));
check->setObjectName("filepath");
connect(check,SIGNAL(clicked()),this,SLOT(echo()));
ui->listWidget->setItemWidget(lwi,check);
}
Slot:
void MainWindow::echo()
{
qDebug() << sender()->objectName() << "should be remmoved";
}
It is not unique way to solve this problem, but it shows all main things, with signals and slots mechanism, objectName and sender() you can achieve all what you need.
sender() return object which send signal, you can cast it, but if you need only objectName you should not cast.
I'm trying get all the button child widgets of a currently active window. The buttons were created through QDialogButtonBox. I'm trying to get the roles of each button so I can identify which button is the OK, CANCEL, or SAVE button. However I'm getting an error with the following code:
QWidget *pWin = QApplication::activeWindow();
QList<QPushButton *> allPButtons = pWin->findChildren<QPushButton *>();
QListIterator<QPushButton*> i(allPButtons);
while( i.hasNext() )
{
QDialogButtonBox *pButtonRole = new QDialogButtonBox();
QDialogButtonBox::ButtonRole role = pButtonRole->buttonRole(i.next());
qDebug() << "buttonRole: " << role << endl ;
//the value of role here is -1, which means it's an invalid role...
}
I'm getting a negative value when getting the button's role :(
Can somebody tell me what's wrong with the code?
You can't call a non-static method like that. You need to have the QDialogButtonBox variable and call that particular instance for buttonRole() to work.
QDialogButtonBox::ButtonRole role = myButtonBoxPtr->buttonRole(i.next());
You are creating a new empty QDialogButtonBox which has no idea about buttons in allPButtons list. Calling buttonRole() on them returns -1 (InvalidRole) because buttons are not in that button-box.
You must do as jkerian wrote and myButtonBoxPtr must point to the QDialogButtonBox which is already in your window.
You can try something like this (if you have one ButtonBox):
QDialogButtonBox *box = pWin->findChild<QDialogButtonBox *>();
foreach(QAbstractButton* button, box->buttons())
{ qDebug() << box->buttonRole(button); }
I have a QSplitter with two widgets. One of them is static, the other one is supposed to change on the press of a button. But the problem is the widget does not change?
I have a pointer for the widget that is changing - this->content
The widget to switch to is in the pointer named widget.
Here's a code snippet where I switch the widget:
qDebug() << "before: " << this->content;
this->content = widget;
qDebug() << "after: " << this->content;
this->content->update();
this->content->repaint();
My debug output there verifies that the pointer points to the other widget:
before: QLineEdit(0x363850)
after: SCTableView(0x3644c0)
Trying to make it show by calling update() and repaint(), without any success.
Any ideas?
Problem solved. Got help from some people in #qt on freenode. Thanks.
I forgot to call setVisible(true) on this->content after switching to the new widget.