How to tackle this design obstacle in Qt? - c++

I need to draw a form that would have some options on the left, this can be seen in the following diagram:
Now, when a user clicks on OptionA, a separate related layout would be shown on the right.
and when a user clicks on OptionB, a separate related layout would be shown on the right.
My current design approach for such type of a problem is as follows:
Have a form with a horizontal layout with two frames. One frame has the options, while the other frame would be hosting other forms. So, in my case optionA would have a separate form, say formA, OptionB would have its own form, say formB, and OptionC would have its own form, say formC.
Now when ever a user clicks on OptionA the formA would be displayed inside FrameHost, similarly when user clicks on OptionC, formC would be displayed inside FrameHost. My question is if this is a good approach giving each option an independent form?
My other thought is the opposite which is to have all the forms (A, B and C) layouts inside a separate frame inside one form and when user clicks on OptionA the frame that has FormA content would be made visible while others would be hidden. So, one frame would be shown at a time. What would be the best approach to tackle this kind of a problem?

The first approach is OK, but lacks the concept of QStackWidget. I would personally use QStackedWidget for showing the forms depending on the exclusive radiobutton clicked.
The second approach is very hackish because it is trying to immitate the fact that these forms would be displayed in the same place, yet, it would render them vertically tricking on the visible/hidden property.
I would write the code like this:
MyWidget *formA = new MyWidget;
MyWidget *formB = new MyWidget;
MyWidget *formC = new MyWidget;
QStackedWidget *stackedWidget = new QStackedWidget;
stackedWidget->addWidget(formA);
stackedWidget->addWidget(formB);
stackedWidget->addWidget(formC);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(stackedWidget);
setLayout(layout);
connect(myButtonGroup, SIGNAL(clicked(int)), SLOT(setCurrentIndex(int)));

Related

Qt Desktop on Mac: QFormLayout sizing with subpanels

TL;DR: I'm having a grow/shrink probably using embedded forms inside a MainWindow. I'm unsure what to try next.
Okay, I have another sizing problem.
This is a sample app of what I'm trying to do:
When I click on the various toolbar options, I intend to change the central widget contents accordingly. Maybe I should just use a tab widget, but I wanted to do it this way.
In the simplest form, with a widget layout like this:
I set the central widget's layout to Horizontal, and the Inner Widget to FormLayout then set the inner widget's expand rules to expand any expandable fields. As I resize the window, the simple line edit expands and contracts as desired.
When I click the bus icon in the toolbar, I swap out the contents of the central widget with a separate panel. That panel has a widget with a form layout, and is also set to expand and collapse. Here are the layout rules for the second panel:
My trigger code does this:
currentCenter = ui->innerWidget; // In the constructor
currentCenter->hide();
if (v1Form == nullptr) {
v1Form = new V1Form(ui->centralWidget);
}
v1Form->show();
currentCenter = v1Form;
I have tried various orders to this, and I tried using setCentralWidget(). In all cases, the new central area remains a fixed size, even though the original one expands and collapses.
What is working: I can readily change the inner contains for different forms. That's working great. (It took a while to figure it out.)
-or- I can make simple popup forms that grow and shrink properly.
What is not working is grow/shrink when I embed my form inside my central widget or if I use setCentralWidget.
I'm not sure what else to try.
Maybe I should just use a tab widget, but I wanted to do it this way.
You should definitely use a QTabWidget as your central widget. It is designed specifically for your use case, and it will greatly simplify your code.
My trigger code does this:
currentCenter = ui->innerWidget; // In the constructor
currentCenter->hide();
if (v1Form == nullptr) {
v1Form = new V1Form(ui->centralWidget);
}
v1Form->show();
currentCenter = v1Form;
With a QTabWidget, your trigger code can be simplified to:
ui->innerTabWidget->setIndex(1).
You don't need to dynamically construct a V1Form. Simply use Qt Designer to create multiple pages in your QTabWidget and implement all your subpanel widgets within your MainWindow.ui.
(Nonetheless, if you want to implement each subpanel in its own separate *.ui file, you can still promote each page in your QTabWidget to your custom widget.)
What is not working is grow/shrink when I embed my form inside my central widget or if I use setCentralWidget.
To address your original symptoms: Your widgets don't grow/shrink because you didn't put them inside a layout that is part of your main window.
I found a solution doing it the way I started. I had to add one line of code:
void MainWindow::switchForm(QWidget *widget) {
if (centralForm != widget) {
if (centralForm != nullptr) {
centralForm->hide();
centralForm = nullptr;
}
if (widget != nullptr) {
centralForm = widget;
centralForm->show();
ui->centralwidget->layout()->addWidget(centralForm);
}
}
}
void MainWindow::on_actionSetup_triggered()
{
if (setupForm == nullptr) {
setupForm = new SetupForm(ui->centralwidget);
}
switchForm(setupForm);
}
The missing line -- adding my new form to the layout:
ui->centralwidget->layout()->addWidget(centralForm);

QListWidgetItem with Radio Button

I'm working on my first QT application and I have a problem with QListWidgetItems.
I will be having different kind of list.
for checkboxed list using:
listElement[i]->setFlags(Qt::ItemIsEnabled);
listElement[i]->setCheckState(Qt::Unchecked);
works exactly as wanted.
But now I want a Radio Button list. so my question is in two parts
can use the same logic that I used for checkBox to create Radio Buttons?
I have used:
listElement[i]->setFlags(Qt::ItemIsEnabled);
QRadioButton *radio1 = new QRadioButton(0);
dlList->setItemWidget(listElement[i],radio1);
this will display Items in the list with a radio Button, the problem is that the text is Over the Radio Button:
going to try to demonstrate without image
This is a test
o
for elements 1
instead for checkbox I have
This is a test
[]
for element 1
how can I get the radioButton to align correctly with text?
New Questions:
Thanks alot for the answers my text is next to my RadioButton now.
Only thing there is no WordWrap, My text is Longer than maximum Size of the RadioButton. How can I get it to wordwrap:
rButton = new QRadioButton();
rButton->setFixedSize(LIST_TEXT_WIDTH_WO_ICON, LIST_TEXT_HEIGHT);
rButton->setStyleSheet("border:none");
rButton->setFont(segoe18Font);
rButton->setText("This is just a test for elementsss of type euh!!!");
rButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
dropListWidget->setItemWidget(listElement, rButton);
As you may have read, there are two approaches to achieve what you want.
The most flexible one: use a QListView, implement a new delegate and a model if necessary.
Keep using the classic item-based interface (QListWidget) and change the item's widgets either by sub-classing QListWidgetItem or calling QListWidgetItem::setItemWidget.
Since the question points towards the second one, I'll try to provide the simplest item-based solution.
The following piece of code generates the list widget in the picture.
QListWidgetItem *it;
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item 1")));
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item 2")));
// .
// .
// .
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item N")));
where ui->listWidget is a pointer to the QListWidget that holds the items.
I hope this helps. As far as I understand, that's what you need.

Is it possible to inherit QVBoxLayout and set it as layout in QWidget?

What I'm trying to accomplish:
Create 2 classes that inherit QVBoxLayout simply to set up each class with a series of different objects.
e.g.:
Class 1 (inherits QVBoxLayout), has QLabels to show an appointment and those labels set up with this->addWidget(labels);
Class 2 (inherits QVBoxLayout), has QLineEdits (and so on) to edit an appointment and those objects are also set up with this->addWidget(lineedits);
Is it possible to have a QWidget class then switch between these 2 layouts by calling this->setLayout(class1_object); and this->setLayout(class2_object);?
Or how would you suggest the swapping of the active objects on the widget (when clicking the edit button on the view-part or the save button on the edit-part)?
Simply use object->setShown(false);?
IMO, it's easier to use QTabWidget here.
Make a QTabWidget with 2 tabs. On Tab1, put your labels. On Tab2, put your edits. Call Tab2 something like "Edit the appointment". Now, use the currentChanged() slot for catching the tab switching.
If saving edits should be simple, all you will need to do is just to copy the edited data from edits to labels, and vice-versa.
If saving requires more than that, e.g. you want a confirmation dialog, you can permit the user to change back to Tab1 until some condition is met:
void MainWindow::on_tabWidget_currentChanged(int index)
{
//if the user is trying to go back to Tab1 (where the labels are)...
if(index == 0)
{
//...and if user didn't accept something, we just return him to the current tab
//It's probably a good idea to tell him what went wrong, too :P
if(!userAcceptedSaveDialog())
ui.tabWidget.setCurrentIndex(1);
}
}

Remove QLayoutItem from a Layout, but still use it later on?

Here is the environment first:
I have a self defined "Property Editor" which is a QGroupBox (derives from QWidget)
Currently I have a class let's call it "Holder", which has a reference to two of the Property Editors.
Now I have multiple "Holder" classes and one vertical QVBoxLayout (called Sidebar).
In this layout I want both of the Property Editors of the currently selected Holder class to be displayed.
And there is the issue:
When the user selects another holder class, I want the Property Editors of the previously selected Holder class to disappear, and add the Property Editors of the new selected Holder class.
Selecting another Holder class works once. But when I select the first Holder class again, The editors don't seem to change. Why? Does "takeAt(..)" destroy the reference in the holder class? How can I get the desired behavior?
Here is the code, thanks in advance:
void App::setSelection(Holder * holder){
if(m_currentlySelected == holder) return;
m_viewer->sideBarRemoveAt(0);
m_viewer->sideBarInsertAt(0, holder->firstPropEditor);
m_viewer->sideBarRemoveAt(1);
m_viewer->sideBarInsertAt(1, holder->secondPropEditor);
m_currentlySelected = holder;
}
void QtViewer::sideBarRemoveAt(int i){
m_sideBar->m_layout->takeAt(i);
}
void QtViewer::sideBarInsertAt(int i, QWidget * widget){
m_sideBar->m_layout->insertWidget(i, widget);
}
QLayout::takeAt() doesn't remove the widget of the QLayoutItem from its parent widget. The only reason it may seem to work the first time is probably because the other widgets were above (z-index wise) the first ones.
Rather than playing with the layout, you could
just hide/show your 2 PropertyEditor whenever the holder changes, hidden items don't generate holes in the layout, the next visible item is displayed as if the hidden items were not part of the layout, or
use a QStackedWidget to stack all the PropertyEditor at the same place and select which one is displayed (with QStackedWidget::setCurrentIndex()).
Does "takeAt(..)" destroy the reference in the holder class?
No, this method removes the QLayoutItem from the layout. See reference page for takeAt. This class doesn't release the layout item (it is your responsibility to do).
But when I select the first Holder class again, The editors don't seem
to change. Why?
I am not quite clear what you are trying to achieve (not enough code in your example), but if you are trying to change the layout using QLayoutItem's, then it is the simplest to create new layout and add items you want to display to it. Or simply, remove all items from the layout, and add the items that should be visible.

Cannot copy Qwidgets in tab to a new tab

Ok so I have been going insane trying to find an answer to this for a day now. What I am trying to do is make a copy of all the widgets in a tab. I want to transfer the copy to a new tab. Think of a form in a tab, and when you click "New Tab" it displays the same form but blank. I am new to QTCreator so any pointers would be great.
Thanks in advance!
Any class that derives from QObject is not copyable. If you want to "copy" a widget, then perhaps a model-view architecture would be a better fit where you have two different views representing the model.
Another thought: you could have each class that needs to be copyable create a state object that could then be used to set the state on the copy.
Since you're just trying to display the same form in multiple places, you could do something like this.
First, create your form which I'll assume is called MyForm:
class MyForm: QWidget {...};
Then, in the parent form:
void ContainerForm::ContainerForm(...) {
connect(pbAddNewTab, SIGNAL(clicked()), SLOT(addNewTab()));
}
void ContainerForm::addNewTab() {
tabWidget->addTab(new MyForm(this));
}
You may need to pull out the new so you can setup signals and slots, etc.
If the new form is blank then it is not a copy. All you need to do is create a new instance of your form widget.