I haveing 2 FORMS in my Qt Project, the SplashForm and the MainForm!
The SplashForm start's first and when the user presses the button 'Connect' then the MainForm opened!
In SplashForm, i have some comboBoxes with values which user can choose,
my problem is that I want to pass those values from SlashForm comboBoxes that users have chosen to MainForm class and save them in private members of class, and then show them in MainForm in labels.
So far I can't find anything useful about how to pass values from forms and classes with Qt.
I have tried the Signal/Slot example but I didn't work.
Any Suggestions?
In event handler for 'Connect' button, open MainForm after assigning combobox value to SplashForm.
With
connect(m_button, SIGNAL (released()),this, SLOT (handleButton()));,
void SplashForm::handleButton()
{
MainForm* popup = new MainForm(this);
popup->setLabel(m_comboBox->currentText());
popup->show();
}
Related
I use a QWidgetAction to add a header to a context menu (that will also show up on Windows, no matter what style is used, in contrast to addSection(), which does not always actually display the title).
The action's widget is a QLabel. It's text is changed by each invocation of the context menu. The menu is setup in the constructor of my class, and the QWidgetAction is added like so (all m_ variables are member variables declared in the header):
m_contextMenu = new QMenu(this);
m_menuTitle = new QLabel;
m_menuTitle->setAlignment(Qt::AlignCenter);
m_menuTitle->setMargin(4);
QWidgetAction *titleAction = new QWidgetAction(m_contextMenu);
titleAction->setDefaultWidget(m_menuTitle);
m_contextMenu->addAction(titleAction);
m_contextMenu->addSeparator();
When the menu is requested, the text of the label is changed and the menu is displayed like so:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
m_contextMenu->exec(place_to_display);
When the label's text is set for the first time (with a short text the label's text is set to), everything is fine:
but when it's set to some longer text, the size remains the same and the text is cropped:
I tried to fix this, but the only working solution I found was to define the QActions displayed in the menu in the constructor, owned by this, setting the label's text, clearing the menu and adding the actions again, like so:
m_contextMenu->clear();
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
m_contextMenu->addAction(m_menuTitleAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(m_editAction);
m_contextMenu->addAction(m_deleteAction);
m_contextMenu->exec(place_to_display);
Is there a way to resize the title without rebuilding the menu each time?
The solution is to send a resize event instead:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
QResizeEvent re(new_size, m_contextMenu->size());
qApp->sendEvent(m_contextMenu, &re);
This will set the QMenu's internal itemsDirty flag and will force geometry recalculation when the menu is shown. Note that the new size in the event does not matter, as the menu will aways resize based on its sizeHint()!
The QResizeEvent solution didn't really work for me (with a more complex widget), I found the generic solution by reading the QMenu and QAction source code.
m_widget->installEventFilter(this);
// and in my case m_widget->layout()->setSizeConstraint(QLayout::SetFixedSize);
bool SomeClass::eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_widget && event->type() == QEvent::Resize) {
// Force QMenu to recalculate the geometry of this item
QActionEvent e(QEvent::ActionChanged, this);
qApp->sendEvent(m_contextMenu, &e);
}
...
}
QActionEvent triggers everything we need in QMenu: recalculating geometries, resizing the menu to its new size (if it's visible), etc.
This answer extends user362515's answer.
There is little more effort required if you change the size of a hidden widget action (e.g., because of its menu is currently collapsed).
Create a new class ActionWidget which derives publicly from QWidget.
Then override the showEvent method and implement it like this:
void ActionWidget::showEvent(QShowEvent* event)
{
QResizeEvent resize_event(QSize(), parentWidget()->size());
parentWidget()->adjustSize();
qApp->sendEvent(parentWidget(), &resize_event);
QWidget::showEvent(event);
}
Notice that adjustSize must be called on the parent widget of the action widget and the event must be sent to the parent widget.
Of course, you must also reimplement QWidgetAction::createWidget such that it returns an instance of the ActionWidget-class and make sure that ActionWidget reports a proper (updated) size hint.
i'm a beginner so if it possible explain to me how to pass variable between 2 forms for example:
i have the first Form called : Send.ui - send.cpp - send.h
and the second form called : Receive.ui - receive.cpp - receive.h
we gonna suppose that i have a variable called age=25 in Send.cpp and a push button
i want that when i press the push button he will open the second form Receive.ui and i will have a variable in this second form age=25
that's meen if i change the variable in the Send.cpp he will be automatically changed in Receive.cpp
and thanks in advence
For communication between objects, Qt has a mechanism called Signals and Slots.
Here is a example of how you can use signals and slots:
In this example I will use spinboxes to visually represent the variable(age) that you mentioned.
1. Open Receive form
In Send, create the button that will open the receive form.
send.h
public:
QPushButton *pushButton;
send.cpp
pushButton = ui->pushButtonSend;
Now create a slot in mainwindow to show receive form.
mainwindow.cpp
void MainWindow::showReceiveForm()
{
receiveForm->show();
}
mainwindow.h
private slots:
void showReceiveForm();
Now connect clicked signal from the push button to the slot in mainwindow.cpp. This will call the slot function everytime the button is clicked.
connect(sendForm->pushButton,SIGNAL(clicked()),this,SLOT(showReceiveForm()));
2. Send Age value
To send the age value to receive form, whenever it's value is changed in send form, connect the valueChanged signal from the QSpinBox in send form to a slot in receive form.
send.h:
public:
QSpinBox *spinBox;
send.cpp
spinBox = ui->spinBoxSend;
Slot in receive.cpp:
void Receive::receiveAge(int age)
{
ui->spinBoxReceive->setValue(age);
}
Now connect signal and slot in mainwindow.cpp.
connect(sendForm->spinBox,SIGNAL(valueChanged(int)),receiveForm,SLOT(receiveAge(int)));
In this example, I used predefined signals from QPushButton and QSpinBox, but you can create your own signals and emit them whenever.
Define custom signals in the header files:
signals:
void exampleSignal(int someArgument);
And emit them with the "emit" keyword.
emit exampleSignal(somenumber);
I have created Qt GUI application. It consists of QGraphicsScene, and items (QGraphicsItems) are added to them by pressing or triggering pushbuttons. Each item added to the scene are members of different classes derived from QGraphicsItem. Now, my challenge is to delete an added item off the scene through one of the following mechanisms:
1) Right click an added item, create a context menu, and then use
scene->removeItem(addedItem);
2) Double click the item which deletes the item
3) Select an item using the flag ItemIsSelectable, and then delete the item by pressing the delete key on the keyboard
But having said that, as a newbie to Qt, I'm unable to do number 1 since the context menu doesn't show up when right clicked. In the case of number 2, I used signals and slots, a single emitted whenever an item is double clicked, and a slot in the mainWindow absorbs the signal and removes the item. But this way, the programs fails to compile because of the error "duplicate symbol found" when I add a Q_OBJECT macro to the header file of the item's class.
So my final option is to select an item on the screen and propane the keyboard signal to delete the item by pressing delete. How can be this done? Please give me advice if any of the above methods can be easily done in case I might be doing it completely wrong.
P.S. : I know there a lot of queries regarding deleting QGraphicsItem off QGraphicsScene, but none of them document a solid answer.
... I'm unable to do number 1 since the context menu doesn't show up when right clicked.
There are two possible methods to accomplish this:
Create a QWidget based menu, attached to the QGraphicsView.
Create your own menu item, derived from a QGraphicsItem.
Whilst the 2nd method will take more time, it's probably a better system in my opinion, as it will feel more integrated with the item you're deleting in the scene. The first method is also possible and if it's not working, then you could post an example question on SO.
2, I used signals and slots, ... because of the error "duplicate symbol found" when I add a Q_OBJECT macro to the header file
It sounds like you're trying to add the signal / slot functionality to a class derived from QGraphicsItem. You don't need to do this. Qt provides the QGraphicsObject class, which you can derive from, instead of QGraphicsItem, if you want signals and slots on items in a QGraphicsScene.
propane the keyboard signal to delete the item by pressing delete.
I assume you mean to 'propagate' keyboard signals. By overriding the QGraphicsScene and its keyPressEvent or keyReleaseEvent, you can get a list of selected items and delete them from the scene. Here's a skeleton example: -
class MyScene : public QGraphicsScene
{
protected:
void keyReleaseEvent(QKeyEvent * keyEvent);
};
void MyScene::keyReleaseEvent(QKeyEvent * keyEvent)
{
if(keyEvent->key() == Qt::Key_Backspace)
{
QList<QGraphicsItem*> selectedItems = selectedItems(); // get list of selected items
foreach(QGraphicsItem* item, selectedItems)
{
removeItem(item);
delete item;
}
}
}
You're seeking a lot of answers, Not so much how to handle QGraphicsItem or QGraphicsScene.
1) Right click an added item, create a context menu, and then use scene->removeItem(addedItem); here.
2) Double click the item, which deletes the item - you'll need to handle double clicks, and hit-testing the QGraphicsItems, you'll have to implement mouseDoubleClickEvent(QMouseEvent *e) and pass e's pos() to this to determine if a QGraphicsItem was clicked or not.
3) Select an item using the flag ItemIsSelectable and then delete the item by pressing the delete key on the keyboard - I'm not sure about the ItemIsSelectable flag. However, you'll need #2. And to learn how to handle keyboard input, by overriding this:
void QWidget::keyPressEvent( QKeyEvent *k ){
switch ( tolower(k->ascii()) ) {
case '\x08': \\backspace
break;
case '\x7F': \\delete
break;
}
}
There's also the Qt::key enumeration, which has Key_Backspace, and Key_Delete. It can be tested against the QKeyEvent::Key()'s return if you don't like dealing with ASCII character codes.
I have created a Qdialog box using the Qt creator designer as shown below:
When I need to display it, I'm instantiate the class dialogoverwrite (.cpp, .h and .ui)
DialogOverwrite *OverwriteDialog = new DialogOverwrite;
OverwriteDialog->exec();
OverwriteOption = OverwriteDialog->result()
My issue is that I want to get the QDialogButtonBox result but I do not know how. the current code, returning the result of the OverwriteDialog but it's not returning any QDialogButtonBox::Yes, QDialogButtonBox::YesToAll ...
How to catch the QButtonGroup result and not the QDialog result.
In the same way, If I want to change the label value from "File(s) and/or Folder(s)" to another label, how to access to this QLabel ?
Thanks for your help
When you pressed QDialogButton it was emit signal clicked(QAbstractButton*) by catching this signal you can identify which action button pressed.
Please go through following link it would be help you.
Qt: How to implement QDialogButtonBox with QSignalMapper for non-standard button ??
Well the standard way to do this is to handle the result by connecting it. So you could do:
connect(this, SIGNAL(clickedDialogButton(QAbstractButton*)),
SLOT(dialogButton(QAbstractButton* aButton)));
Next you would create a function in your class called dialogButton (for example) and have that handle the result:
void MyUI::dialogButton(QAbstractButton* aButton) {
// Obtain the standard button
StandardButton button = buttonBox−>standardButton(button);
// Switch on the type of button
switch (button) {
case QDialogButtonBox::YesToAll:
// Do the thing you would like to do here
break;
// add some more cases?
}
}
You could also check for the signal given by the QButtonGroup. Something like: void QGroupButton::buttonClicked(QAbstractButton* button) would work in the same way.
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);
}
}