How can I make a child widget standalone? - c++

Suppose I have a main Widget, which is used to view some objects. The names of those objects are stored in a QListWidget. Now when a user selects one object (one item of the QListWidget), I want to open another widget in a separate window which takes the name of the object as an argument.
class MainWidget
{
Q_OBJECT
public slots:
void openSelection();
};
class ChildWidget
{
public:
ChildWidget(QString name, QWidget* parent = nullptr);
};
void MainWidget::openSelection()
{
QString selectedObjectName = ui->objectsNamesList->selectedItem()->text();
ChildWidget* detaildedWiew = new ChildWidget(selectedObjectName, this);
detaildedWiew->show();
}
When I do this, the child widget opens, but it has no space of its own. It is locked in the area of the parent. I need to set the children free, to run around the screen freely, independent of their parent. How can I do this? Is there some Qt way, or do I have to define some "pseudo child" relationship and develop a system to properly delete the pseudo children?

You can use QWidget::setWindowFlags(Qt::Window) to make your widget a separate window.
Also have a look at Qt::WindowFlags.

Not sure I got the question right...
The default constructor of QWidget may accept two arguments:
QWidget *parent = 0 is the parent of the new widget. If it is 0 (the default), the new widget will be a window. If not, it will be a child of parent, and be constrained by parent's geometry (unless you specify Qt::Window as window flag).
Qt::WindowFlags f = 0 (where available) sets the window flags; the default is suitable for almost all widgets, but to get, for example, a window without a window system frame, you must use special flags.
So, if you pass anything but NULL to parent, your wiget will not be a separate window, unless you set the second parameter as QT::Window. This is what's happening for you. So you'll need to either set the flag QT::Window, or make your own class, derive it from QWidget, and write a constructor that takes an additional argument which will be the pointer you need, while getting NULL as parent.

Related

How can I create a QVector or other container which can contain different widgets?

I am developing a GUI with Qt5, and in the main window of this GUI, it contains at least 4 tab widgets, and each tab widget will contain serval different child QWidgets, such as QLineEdit, QSpinBox, QLCDnumber, etc. Then when I open the tab, all its child widgets will appear.
Thus, for each tab, I decided to create a QVector(or another container type) to contain its all child Widgets,e.g.:
QVector<QWidget*> wids;
for the first tab widget, if it has the following children:
QLineEdit* line=new QLineEdit(this);
QLCDNumber* lcd=new QLCDNumber(this);
QSpinBox* spn=new QSpinBox(this);
then somehow I would like to do
wids.append(line);
wids.append(lcd);
wids.append(spn);
and next,I want to operate each widget inside the tab,e.g.:
wids[0]->setText("good");
wids[1]->display(1);
wids[2]->setRange(0,10);
I know I need to use dynamic_cast<...>, but I DO NOT KNOW how to do that,is ther anyone could give me some advice?
many thanks!
QLineEdit, QLCDNumber and QSpinBox already inherit from QWidget. So if you put those in a QVector (or any container for that matter, could be a std::vector<QWidget*>) you have to deal with QWidget pointers.
As you correctly stated:
wids.push_back(line);
wids.push_back(lcd);
wids.push_back(spn);
To get your respective classes back, for example QLineEdit back, you need to downcast from QWidget to QLineEdit, QLCDNumber or whatever else inherits from QWidget.
QLineEdit * line = dynamic_cast<QLineEdit*>(wids[0]);
This of course assumes that you know exactly at which position the object is located. You can of course test if your cast was successful:
if( line == nullptr )
{
// cast failed, either wids[0] is invalid or does not derive from QWidget
}
else
{
// cast was successful, use 'line' as regular QLineEdit.
}
A one-liner, although being quite unsafe, would be:
dynamic_cast<QLineEdit*>(wids[0])->setText("myText");

How to retain set value on QSpinBox in QWidget when visiting this widget everytime?

I am having QSpinBox in QWidget where i set some value. Whenever i visit this widget next time, the spinbox takes initial value as zero instead of whatever value I set before.Is anyone having idea about it?
Thanks in advance.
Dialog:
Spin_Box::Spin_Box(QWidget parent)
: QDialog(parent),ui(new Ui::Spin_Box)
{
ui->setupUi(this);
/ Settings for title bar /
ui->headingTextEdit->setText("SPIN BOX");
/ Settings Range for Time spin boxes */
ui->fromHourSpinBoxShift1->setRange(0,23);
ui->fromMinSpinBoxShift1->setRange(0,59);
ui->fromSecSpinBoxShift1->setRange(0, 59);
}
Slot where dialog is opened:
MainWindow::on_actionSpin_Box_triggered()
{
Spin_Box Spin_BoxDialogue;
Spin_BoxDialogue.setModal(true);
Spin_BoxDialogue.exec();
}
As vahancho and Oleg Olivson stated in the comments, each time the function on_actionSpin_Box_triggerd() gets called a new instance of your Dialog is created. Therefore all values are those initialized.
If you want to keep previously inserted values you have to, either create the dialog only once (within your class where on_actionSpin_Box_triggered() is implemented) and reuse it by calling only exec() each time, or you store the values of the dialog in settings/... or whatever, to load them each time the dialog is opened.
Depending whether you would also need them after a program restarts, only the second approach would help.
Make Spin_BoxDialogue a pointer to Spin_Box a member of your MainWindow. So "MainWindow.h" should have this line inside class MainWindow's private section:
Spin_BoxDialogue* m_foo;
Initialize it and set it to Modal in MainWindow's constructor. Note that Spin_BoxDialogue should have a constructor that takes a pointer to its parent to take advantage of Qt's memory management.
MainWindow::MainWindow() : m_foo(new Spin_BoxDialogue){m_foo->setModal(true);}
Then change MainWindow::on_actionSpin_Box_triggered to this:
void MainWindow::on_actionSpin_Box_triggered(){m_foo->show();}

QWidget created in an aux method does not show/draw

I have a QWidget based class that I need to instantiate from another object.
If I create the widget in the body of its parent widget class it is all good:
new NodeWidget(rootItem, this); // this works
But when I use the aux method the widget is created, but never drawn.
rootItem->createWidget(this); // internally rootItem does the same thing as above
The method itself:
void createWidget(QWidget * target) {
if (!_ui) _ui = new NodeWidget(this, target);
...
}
The way I see it, both approaches do the same thing, but the first one works while the second one does not. The NodeWidget constructor runs, but the widget does not appear in the parent widget and the paintEvent is never called. Any ideas why?
EDIT: This is certainly odd, I noticed that the following line:
new QPushButton(this);
works when called in the constructor of the parent widget, but not when called from the mousePress event. What IS the difference?
Do you call show() for your custom widget?
If the child widget is created after it's parent is already showed the parent-child relationship can't show the child too, so you need to explicitly call show().
But when the widget is added in the constructor, the parent isn't showed yet and then when the parent is showed it automatically shows all the children that were not explicitly hidden.

Why do we pass "this" pointer to setupUi function?

I'm fairly new in QT. Taking below fairly simply explain from qt docs :
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
private:
Ui::CalculatorForm ui;
};
and implementation of constructor
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this); // <-- Question below
}
Q: I was wondering why do we pass this pointer to setupUi function?, what does it do ?
So that the dialog will have the caller as parent, so that eg when the parent is closed the dialog can be closed automatically. Generally all gui elements have a pointer to their parent.
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
These are auto generated slots which exactly match the naming of the gui elments in QtDesigner. They are only meant to do the direct hookup to those gui elements and so should be dealt with in this class. If these signals were extended to other classes then any change in the gui would require changing a lot of other code which doesn't need to know details of the gui.
In the handler slot for the specific gui element you can then emit another more general signal to the rest of the app.
The only widget that setupUi doesn't create is the widget at the top of the hierarchy in the ui file, and as the Ui::CalculatorForm class instance doesn't know the widget it has to fill, it (this) has to be passed explicitly to the class at some point.
this or any other widget you would pass to it, is used as the parent to all other subwidgets. For example, you could fill a widget without inheritance like this:
QWidget *widget = new QWidget;
Ui::CalculatorForm *ui = new Ui::CalculatorForm;
ui->setupUi(widget);
widget->show();
But really, it would be easier to understand if you read the content of the uic generated file (probably named ui_calculatorform.h).
setupUi creates the instances of widgets (QLabel, QTextEdit and so on). The [user interface compiler] (http://qt-project.org/doc/qt-4.8/uic.html) gets information for you from the .UI form and generates widget-creation code in the generated moc source files.
The manual way of creating widgets without using the Qt Designer or a UI file would be like so:
QWidget* pWidget = new QWidget(this);
I think it is to add the caller widget to the layout of this UI.
This widget will be the toplevel widget.
Martin Beckett answer might be correct as well, as what he described is a common behavior in Qt (cf the 'parent' argument in most of widget's derived class constructor)
Note that you have alternative ways how designer can auto-generate code.
In this case you have a separate 'UI' class for this code which is not QObject so it also is not a QWidget.
Auto generated code needs information about parent widget and to make auto-conections of slots and signals so this is why you have to pass this.
This pater is less intrusive then other pasterns (that is why it is default). You can also try alternative patters (check Qt Creator Designer options), but I recommend you to see what is generated by designer tools in default settings.

QtT How To Save Data/State When Changing Central Widgets In QMainWindow

I have inherited the QmainWindow class to use as the mainwindow for the application that I am building.
I have set the central widget as a pointer to another class, that I have created.
//main window constructor
postEntryWidget = 0; // null pointer to another class that extends QWidget
dataEntryWidget = new Data_Entry_Widget; //extends QWidget
setCentralWidget(dataEntryWidget); //set the widget in the main window
When the user clicks on an action, this sets the central widget to another pointer to another widget class.
/*
*this is the implementation of the slot that would be connected to the QAction
*connected to the postEntryWidget slot
*/
if(!postEntryWidget)
postEntryWidget = new Post_Entry_Widget;
setCentralWidget(postEntryWidget);
/*
*this is the implementation of the slot that would be connected to the QAction
*connected to the dataEntryWidget slot
*/
if(!dataEntryWidget)
dataEntryWidget = new Post_Entry_Widget;
setCentralWidget(dataEntryWidget);
This breaks when switching back and forth between views. And If I add a null point to the preceding view I lose the data when I go back to that view.
/*
*this is the implementation of the slot that would be connected to the QAction
*connected to the postEntryWidget slot
*/
dataEntryWidget = 0; //set the previous widget to a null pointer but loses data
if(!postEntryWidget)
postEntryWidget = new Post_Entry_Widget;
setCentralWidget(postEntryWidget);
How would I keep the state between the two views without creating a custom data structure or is this bad practice. I am most familiar with php and web dev so I am not sure if this is even the best way to go about this.
Thanks in advance
Not totally sure what your goal is. But if you are trying to permit someone the ability to go back to something they were working on, then perhaps you'd be better off using a tab widget instead of hiding the existence of that work?
QTabWidget documentation
Qt Tabbed Dialog example
So you'd make that your central widget, and plug the Post_Entry_Widget and Data_Entry_Widget instances under that. An advantage of that is that Qt manages the tab switching for you.
If you don't want tabs there is also a QStackedWidget, which just lets you programmatically switch between a set of widgets.
It is more complicated than it seems. The problem is, that when setCentralWidget() is called, current centralWidget() gets deleted. In order to preserve its contents, you need to remove it from the window by reparenting it to NULL or 0. Try to change your code to:
if(!postEntryWidget)
postEntryWidget = new Post_Entry_Widget;
if (centralWidget()) centralWidget()->setParent(0); //reparent if exists
setCentralWidget(postEntryWidget);
/*
...
*/
if(!dataEntryWidget)
dataEntryWidget = new Post_Entry_Widget;
if (centralWidget()) centralWidget()->setParent(0); //reparent if exists
setCentralWidget(dataEntryWidget);