sizeHint() of a QWidget doesn't work if the creation of a QMainwindow is triggered by clicking context menu
-
Hi,
this issue has confused me for two weeks and I finally decided to ask for a help here.My problem:
I have a MainWindow which has a QTabWidget as its central widget and a bottom dock widget called "test center", like below:
the corresponding source code is as following:
MainWindow::MainWindow(QWidget *parent) : FrameWin(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); //set a QTabWidget called mainTab as MainWindows's central widget setCentralWidget(mainTab); //addOneTab("new 1"); //create a control center and attach it as a dock to MainWindow QDockWidget *dock = new QDockWidget(this); TestControl* control = new TestControl(this); dock->setParent(this); dock->setWindowTitle("control center"); dock->setWidget(control); addDockWidget(Qt::BottomDockWidgetArea, dock); }
now I hope that I can add a tab on the mainTab, this tab has a left dock widget called "Hello" with default width=300 and a QTexEdit as its central widget. note MyWidget is a subclass of QWidget and override the sizeHint() function like this:
class MyWidget : public QWidget { public: virtual QSize sizeHint() const { return size; /* Define the initial size of the dock here */ } QSize size; };
void MainWindow::addOneTab(QString s) { //create a QMainWindow as a tab page of QTabWidget QMainWindow * mWin = new QMainWindow(this); mainTab->addTab(mWin, s); mainTab->setCurrentIndex(mainTab->count() -1); //crete a dock widget and set its default width = 300, attach this dock to QMainWindow QDockWidget *dock = new QDockWidget(mWin); dock->setParent(mWin); dock->setWindowTitle("Hello"); MyWidget *wi = new MyWidget; wi->setParent(dock); wi->size=QSize(300,100); dock->setWidget(wi); // dock->setVisible(true); mWin->addDockWidget(Qt::LeftDockWidgetArea, dock); //create a central widget for the QMainWindow QTextEdit * wi2 = new QTextEdit; mWin->setCentralWidget(wi2); }
it works fine if this tab is added from MainWindow's construction function ( I uncommented "addOneTab("new 1");" in the constructor function), like following:
However, now I hope the add tab operation is triggered by clicking the contex menu item -"my review" of the QTreeWidget in the test center:
TestControl::TestControl(QWidget *parent) : QWidget(parent), ui(new Ui::TestControl) { ui->setupUi(this); m_parent = parent; ui->m_tree->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->m_tree, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onJobTreeShowContextMenu(QPoint))); } void TestControl::onJobTreeShowContextMenu(QPoint pos) { QMenu menu; QIcon icon = QIcon(); QAction* OpenReview = new QAction(icon, "my review", &menu); connect(OpenReview, SIGNAL(triggered(bool)), this, SLOT(onOpenJobReview())); menu.addAction(OpenReview); menu.exec(ui->m_tree->mapToGlobal(pos)); menu.exec(); } void TestControl::onOpenJobReview() { ((MainWindow*)m_parent)->addOneTab("new x"); }
the tab can be added, however, the "Hello" dockwidget's default width is not correct, it looks like it get expanded.
I really don't know why this happen, is there anyone can help me?
version: Qt 4.8.7
-
Hi and welcome to devnet,
You current code triggers quite a lot of questions, so just a couple of them to get started:
- Why are you creating a full new QMainWindow when calling addOneTab ?
- What is FrameWin ?
For number one you seem to want to have two widgets one beside each other but do you really need a dock widget for that rather than a horizontal layout ?
If the dock widget is supposed to be tightly associated with the text edit, you are going to lose that information as soon as your users are going to start undocking and re-docking them in different "tabs"Since you are mentioning tabs in your code, do you really want dock widgets or are you looking of something like QTabWidget ?
@fanyha said in sizeHint() of a QWidget doesn't work if the creation of a QMainwindow is triggered by clicking context menu:
void TestControl::onOpenJobReview()
{
((MainWindow*)m_parent)->addOneTab("new x");
}This is several levels wrong, if you want your MainWindow to get triggered, use proper signals and slots. Here you make the assumption that you have a parent and that the parent is MainWindow based class. You are also storing that parent as a member variable while Qt already provides a getter for that if really required.
-
@SGaist
really appreciate for your reply.to answer your first 2 questions:
-
Why are you creating a full new QMainWindow when calling addOneTab ?
My answer: sorry, I am a little confused, what do you mean by "a full new QMainWindow"? here I just need to create a QMainWindow to put my dock widgets on, is there any other way to implement this? -
What is FrameWin ?
sorry, I made code looks complex. FrameWin is just a subclass of QMainwindow, mainTab is created in its constructor. now I have removed FrameWin and make mainTab created in MainWindow.
answers to some other questions:
yes, I need dockwidget, in our real project, we use it like this. note what I have shown is just a simple demo to reproduce this issue. it's not our real project source code.
by the way, tab1 's dock widget seems not be able to put on tab2.about the code issue:
void TestControl::onOpenJobReview() { ((MainWindow*)m_parent)->addOneTab("new x"); }
yes, I admit there's an issue here, thanks for point it out. but in my sample source code, m_parent is MainWindow type, so in my simple demo, it won't be an issue to cause the layout issue. and I have changed it to signals/slots.
note I just write this demo to reproduce the layout issue, I am not sure if it's QT's bug, but now it looks like it is.
-
-
@fanyha said in sizeHint() of a QWidget doesn't work if the creation of a QMainwindow is triggered by clicking context menu:
((MainWindow*)m_parent)->addOneTab("new x");
Just a very quick note. Don't use C-style casts like this any longer, they are needlessly dangerous. Use C++ either
static_cast<MainWindow*>(m_parent)->addOneTab("new x");
which asserts if
m_parent
is notMainWindow*
. In your case where you know it is it effectively behaves like your C-cast, but is safer; orMainWindow* mainWin = dynamic_cast<MainWindow*>(m_parent); // or use `qobject_cast` in place of `dynamic_cast` if (mainWin) mainWin->addOneTab("new x"); else .... // whatever
-
Please provide a complete compilable minimal and clean example that shows your issue.
Can you please explain the purpose of your design ?
There's no problem having several QMainWindow in an application however using them like you do currently is a bit strange. Therefore, knowing why you need that many "subwidgets" that are in fact QMainWindows will help us understand what you are trying to achieve.
-
hi @SGaist , to simply describe my issue:
if I click on the menu item of a contex menu, the slot addOneTab() is triggered, and a new tab is shown, but MyWidget in this tab is not shown with width = 300 (the actual result is MyWidget always get expanded ).
If I call addOneTab() in MainWindow constructor function directly, MyWidget in this tab is shown with width = 300, which is as expected.
both operation call addOneTab(), Why this difference happen?below is my source code:
//mainwindow.cpp void MainWindow::addOneTab(const QString& s) { //create a QMainWindow as a tab page of QTabWidget QMainWindow * mWin = new QMainWindow(this); mainTab->addTab(mWin, s); mainTab->setCurrentIndex(mainTab->count() -1); //crete a dock widget and set its default width = 300, attach this dock to QMainWindow QDockWidget *dock = new QDockWidget(mWin); dock->setParent(mWin); dock->setWindowTitle("Hello"); MyWidget *wi = new MyWidget; wi->setParent(dock); wi->size=QSize(300,100); dock->setWidget(wi); // dock->setVisible(true); mWin->addDockWidget(Qt::LeftDockWidgetArea, dock); //create a central widget for the QMainWindow QTextEdit * wi2 = new QTextEdit; mWin->setCentralWidget(wi2); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); mainTab = new QTabWidget(this); //set a QTabWidget called mainTab as MainWindows's central widget setCentralWidget(mainTab); //addOneTab("new 1"); //create a control center and attach it as a dock to MainWindow QDockWidget *dock = new QDockWidget(this); TestControl* control = new TestControl(this); dock->setParent(this); dock->setWindowTitle("test center"); dock->setWidget(control); addDockWidget(Qt::BottomDockWidgetArea, dock); }
//testcontrol.cpp TestControl::TestControl(QWidget *parent) : QWidget(parent), ui(new Ui::TestControl) { ui->setupUi(this); m_parent = parent; ui->m_tree->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->m_tree, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(onJobTreeShowContextMenu(QPoint))); connect(this, SIGNAL(showTab(const QString&)), parent, SLOT(addOneTab(const QString&))); } void TestControl::onJobTreeShowContextMenu(QPoint pos) { QMenu menu; QIcon icon = QIcon(); QAction* OpenReview = new QAction(icon, "my review", &menu); connect(OpenReview, SIGNAL(triggered(bool)), this, SLOT(onOpenJobReview())); menu.addAction(OpenReview); menu.exec(ui->m_tree->mapToGlobal(pos)); menu.exec(); } void TestControl::onOpenJobReview() { //((MainWindow*)m_parent)->addOneTab("new x"); emit showTab("new 2"); }
-
sizeHint, as the name suggests, is a hint. It does not guarantee that your widget will be shown to exactly that size.
-
@SGaist
thanks, so what is a normal way to set a dock widget's default width?
As I know, there's a method that we can install a event filter on the dockwidget's client widget, and set the widget max and min width in its show event. this method works fine.
However, it seems almost every post recommend that we use sizehint() on the dockwidget's client widget. my test result is: it doesn't works fine in my special case.
may I know what is your suggestion to implement that?