Nested QDialog automatically presses a QPushButton inside of it - c++

#include <QApplication>
#include <QDebug>
#include <QDialog>
#include <QPushButton>
#include <QTreeWidget>
#include <QVBoxLayout>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QDialog dialog;
QVBoxLayout layout(&dialog);
QTreeWidget treeWidget;
treeWidget.insertTopLevelItem(0, new QTreeWidgetItem(&treeWidget));
QObject::connect(&treeWidget, &QTreeWidget::activated, [&treeWidget]() {
auto secondDialog = new QDialog(&treeWidget);
auto layout = new QVBoxLayout(secondDialog);
auto button = new QPushButton();
QObject::connect(button, &QPushButton::clicked, []() {
qDebug() << "button clicked";
});
layout->addWidget(button);
secondDialog->show();
});
layout.addWidget(&treeWidget);
dialog.show();
return app.exec();
}
When I activate a QTreeWidget's item by pressing Enter, nested dialog is created and it immediately presses button inside of it. How do I get rid of it?

I solved this by overriding keyPressEvent of the QTreeView that was inside the dialog:
class EnterEatingTreeView : public BaseTreeView
{
public:
explicit EnterEatingTreeView(QWidget* parent = nullptr)
: BaseTreeView(parent)
{
}
protected:
void keyPressEvent(QKeyEvent* event) override
{
BaseTreeView::keyPressEvent(event);
switch (event->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
event->accept();
}
}
};
This way pressing Enter key inside QTreeView doesn't passes to its parent.

Related

Opening child window after n seconds from formation of parent window in Qt C++

I have three windows Mainwindow,firstwindow and secondwindow.I have a pushbutton in mainwindow,When i clicked the push button it opens the firstwindow.Up to this part everything is ok.
What i need is , I need to open secondwindow automaticaly after 2sec of the formation of firstwindow
What is happening now is when i clicking the push button in mainwindow, secondwindow will appear first,and the first window will form only after execution of second window.
I am using qt5 with qtcreator
MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_clickMeButton_clicked()
{
FirstWindow * dlg = new FirstWindow;
dlg->show();
}
FirstWindow.cpp
#include "firstwindow.h"
#include "ui_firstwindow.h"
FirstWindow::FirstWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::FirstWindow)
{
ui->setupUi(this);
connect(this,SIGNAL(winMessage()),this,SLOT(openNewWindow()));
emit winMessage();
}
FirstWindow::~FirstWindow()
{
delete ui;
}
void FirstWindow::openNewWindow()
{
dlg = new SecondWindow;
dlg->show();
}
SecondWindow.cpp
**
#include "secondwindow.h"
#include "ui_secondwindow.h"
SecondWindow::SecondWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::SecondWindow)
{
ui->setupUi(this);
}
SecondWindow::~SecondWindow()
{
delete ui;
}
**
My understading is you want something like this:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QPushButton>
class FirstWindow : public QWidget
{
Q_OBJECT
public:
FirstWindow() : QWidget() { resize(100, 100); }
};
class SecondWindow : public QWidget
{
Q_OBJECT
public:
SecondWindow() : QWidget() { resize(100, 100); }
};
class MainWindow : public QPushButton
{
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include <QTimer>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QPushButton(parent)
{
setText("Click me");
connect(this, &MainWindow::clicked, this, [this] {
FirstWindow* first = new FirstWindow;
first->show();
QTimer::singleShot(2000, this, [] {
(new SecondWindow)->show();
});
});
}
If you prefer to separate the implementations, you can start the timer in the first window; the timer will give time to return to the event loop and actually show the first window.
#include <QTimer>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QPushButton(parent)
{
setText("Click me");
connect(this, &MainWindow::clicked, this, [] {
FirstWindow* first = new FirstWindow;
first->show();
});
}
FirstWindow::FirstWindow()
{
resize(100, 100);
QTimer::singleShot(2000, this, [] {
(new SecondWindow)->show();
});
}
or more precisely, you may wait for the actual show event:
#include <QTimer>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QPushButton(parent)
{
setText("Click me");
connect(this, &MainWindow::clicked, this, [] {
FirstWindow* first = new FirstWindow;
first->show();
});
}
void FirstWindow::showEvent(QShowEvent *)
{
QTimer::singleShot(2000, this, [] {
(new SecondWindow)->show();
});
}

Change QML Label text from a C++ function

I have a Label in QML and I want to change its text value when I click on a button. I have tried many different ways to achieve this, but nothing seems to work properly. I have used QObject::setProperty() and it seems to work when I print the new text value with qDebug(), but it does not refresh on the GUI. What am I doing wrong?
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QSettings>
#include <QQuickStyle>
#include <QtQuickControls2>
#include <QQmlContext>
#include <QIcon>
#include "Controllers/Network/network.hpp"
#include "Controllers/NFC/nfc.hpp"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QIcon::setThemeName("gallery");
QQuickStyle::setStyle("Material");
// Property bindings:
qmlRegisterType<RFS::Communication::Network>("rfs.communication.network", 1, 0, "Network");
qmlRegisterType<RFS::Communication::NFC>("rfs.communication.nfc", 1, 0, "NFC");
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("availableStyles", QQuickStyle::availableStyles());
engine.load(QUrl("qrc:/main.qml"));
if (engine.rootObjects().isEmpty()) return -1;
return app.exec();
}
nfc.hpp:
#include <QObject>
#include <QtNfc/qnearfieldmanager.h>
#include <QtNfc/qnearfieldtarget.h>
namespace RFS::Communication
{
class NFC : public QObject
{
Q_OBJECT
public:
explicit NFC(QObject *parent = nullptr);
Q_INVOKABLE bool getStatus() { return pairingStatus; }
Q_INVOKABLE void changeTextValue();
private:
bool pairingStatus;
};
}
nfc.cpp:
#include <QtQuick>
#include <QQuickView>
#include "Controllers/NFC/nfc.hpp"
void RFS::Communication::NFC::changeTextValue()
{
QQuickView view;
view.setSource(QUrl("qrc:/Views/overview.qml"));
QObject *rootObject = view.rootObject();
QList<QObject*> list = rootObject->findChildren<QObject*>();
QObject *testLabel = rootObject->findChild<QObject*>("testLabel");
qDebug() << "Object" << testLabel->property("text"); // Successfully prints old value
testLabel->setProperty("text", "test1");
qDebug() << "Object" << testLabel->property("text"); // Successfully prints new value
QQmlProperty(testLabel, "text").write("test2");
qDebug() << "Object" << testLabel->property("text"); // Successfully prints new value
}
overview.qml:
import QtQuick 2.12
import QtQuick.Controls 2.12
import rfs.communication.nfc 1.0
Page {
id: page
NFC {
id: nfc
}
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: tabBar.currentIndex
Pane {
id: overviewTab
width: swipeView.width
height: swipeView.height
Button {
id: pairButton
text: qsTr("Pair new receiver")
onClicked: {
nfc.changeTextValue()
}
}
Label {
id: testLabel
objectName: "testLabel"
text: "hei" // I want to change this value
}
}
}
}
Is there any better way to achieve this? Thanks a lot in advance.
Anyone looking for a simple solution, I just came up with this trying to achieve changing label's text on c++ side by pressing a button in QML
Add to main.cpp:
Backend backend;
engine.rootContext()->setContextProperty("backend", &backend);
Create a new class (backend.h & backend.cpp)
In backend.h:
#ifndef CONTROLLERS_H
#define CONTROLLERS_H
#include <Qt>
#include <QObject>
#include <QCoreApplication>
#include <QWindow>
#include <QString>
class Backend : public QObject
{
Q_OBJECT
public:
explicit Backend(QObject *parent = nullptr);
public slots:
void setText();
QString getText();
};
#endif // CONTROLLERS_H
In backend.cpp:
#include "backend.h"
QString text = ""; // don't forget this
Backend::Backend(QObject *parent) : QObject(parent)
{
}
QString Backend::getText()
{
return text; //returns the text you set or didnt in setText()
}
void Backend::setText()
{
text = "text"; // or do anything you want with global QString text
}
In QML:
Label{
id: myLabel
}
Button{
id: myButton
onClicked:{
backend.setText()
myLabel.text = backend.getText()
}
}

How to make QMenu Item checkable in QT

How to give Qmenu item checkable using QT
QMenu *preferenceMenu = new QMenu();
preferenceMenu = editMenu->addMenu(tr("&Preferences"));
QMenu *Mode1 = new QMenu();
Mode1 = preferenceMenu->addMenu(tr("&Mode 1"));
Mode1->addAction(new QAction(tr("&Menu1"), this));
QMenu *Mode2 = new QMenu();
Mode2 = preferenceMenu->addMenu(tr("&Mode 2"));
Mode2->addAction(new QAction(tr("&Menu2"), this));
Mode2->addAction(new QAction(tr("&Menu3"), this));
On QAction I called slot "slotActionTriggered(QAction* actionSelected)"
void csTitleBar::slotActionTriggered(QAction* actionSelected)
{
actionSelected->setChecked(true);
}
How to show small TICK in the selected Menu# so that user can know which is selected
Currently I am able to change to all Menu#, but I need to show a small tick on menu so that the selected one can be easly Identified
Small example:
cmainwindow.h
#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H
#include <QMainWindow>
#include <QPointer>
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
CMainWindow(QWidget *parent = 0);
~CMainWindow();
private slots:
void slot_SomethingChecked();
private:
QPointer<QAction> m_p_Act_Button1 = nullptr;
QPointer<QAction> m_p_Act_Button2 = nullptr;
};
#endif // CMAINWINDOW_H
cmainwindow.cpp
#include "cmainwindow.h"
#include <QtWidgets>
#include <QDebug>
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_p_Act_Button1 = new QAction("Super Button 1", this);
m_p_Act_Button1->setCheckable(true);
m_p_Act_Button1->setChecked(true);
connect(m_p_Act_Button1, SIGNAL(triggered()), this, SLOT(slot_SomethingChecked()));
m_p_Act_Button2 = new QAction("Super Button 2", this);
m_p_Act_Button2->setCheckable(true);
m_p_Act_Button2->setChecked(true);
connect(m_p_Act_Button2, SIGNAL(triggered()), this, SLOT(slot_SomethingChecked()));
QMenu *p_menu = menuBar()->addMenu("My Menu");
p_menu->addAction(m_p_Act_Button1);
p_menu->addAction(m_p_Act_Button2);
}
CMainWindow::~CMainWindow() { }
void CMainWindow::slot_SomethingChecked()
{
if(!m_p_Act_Button1 || !m_p_Act_Button2) {return;}
qDebug() << "Hi";
if(m_p_Act_Button1->isChecked())
{
qDebug() << "The action 1 is now checked";
}
else
{
qDebug() << "The action 1 is now unchecked";
}
if(m_p_Act_Button2->isChecked())
{
qDebug() << "The action 2 is now checked";
}
else
{
qDebug() << "The action 2 is now unchecked";
}
}
Modern connection syntax is preferable.
Checkable items can also be used on context menu as follow :
void MyWidget::initContextMenu()
{
if( _contextMenu)
{
delete _contextMenu;
}
_contextMenu = new QMenu(this);
auto action1 = new QAction("Action Item 1", &_contextMenu);
action1->setCheckable(true);
action1->setChecked(getMyProperty1());
connect(action1 , &QAction::triggered, this, &MyWidget::setMyProperty1);
_contextMenu->AddAction( action1 );
}
void MyWidget::contextMenuEvent(QContextMenuEvent *event)
{
initContextMenu();
_contextMenu.popup(
this->viewport()->mapToGlobal(
event->pos()));
}
bool MyWidget::setMyProperty1(bool state)
{
_myProperty1 = state;
emit MyPropertyChanged(_myProperty);
}

QtToolBar with underlined shortcut key in button text

I have a simple Qt toolbar with text only button Action:
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent)
{
QToolBar* toolBar = new QToolBar(this);
QAction* action = toolBar->addAction("&Action");
QObject::connect(action, SIGNAL(triggered()), this, SLOT(onAction()));
action->setShortcut(QKeySequence("ctrl+a"));
addToolBar(toolBar);
}
I would like to have A in Action underlined to reflect its role as a shortcut key. How to accomplish that?
Standard QAction widget (it is a QToolButton actually) uses stripped version of its text for display: "&Menu Option..." becomes "Menu Option".
You can create a custom QAction widget which does not use stripped text by subclassing QWidgetAction:
MyAction::MyAction(QObject *parent) :
QWidgetAction(parent)
{
}
QWidget* MyAction::createWidget(QWidget *parent)
{
QToolButton *tb = new QToolButton(parent);
tb->setDefaultAction(this);
tb->setText(this->text());// override text stripping
tb->setFocusPolicy(Qt::NoFocus);
return tb;
}
In your MainWindow constructor use it as follows:
MainWindow(QWidget* parent=0) : QMainWindow(parent)
{
QToolBar* toolBar = new QToolBar(this);
MyAction* action = new MyAction();
action->setText("&Action");
action->setShortcut(QKeySequence(tr("ctrl+a","Action")));
toolBar->addAction(action);
QObject::connect(action, SIGNAL(triggered()), this, SLOT(onAction()));
addToolBar(toolBar);
}
Appearence of underline shortcut letters depends on your application style.
Here is an example of a custom style that will force shortcut underline display:
class MyStyle : public QProxyStyle
{
public:
MyStyle();
int styleHint(StyleHint hint,
const QStyleOption *option,
const QWidget *widget,
QStyleHintReturn *returnData) const;
};
int MyStyle::styleHint(QStyle::StyleHint hint,
const QStyleOption *option,
const QWidget *widget,
QStyleHintReturn *returnData) const
{
if (hint == QStyle::SH_UnderlineShortcut)
{
return 1;
}
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
Then you should set that style to your application:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle(new MyStyle);
Widget w;
w.show();
return a.exec();
}

Why doesn't setCentralWidget work?

Here is my class MainWindow :
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
menu* v = new menu(this);
setCentralWidget(v);
}
And my menu class :
menu::menu(MainWindow* parent){
QLabel l = new QLabel("123");
QVBoxLayout* lay = new QVBoxLayout;
lay->addWidget(l);
this->setLayout(lay);
QWidget* a = new QWidget;
QVBoxLayout* lay2 = new QVBoxLayout;
QLabel* ll = new QLabel("456");
lay2->addWidget(ll);
a->setLayout(lay2);
parent->setCentralWidget(a);
}
When I run the program, the window shows 123 but I would like it to show 456.
Is the method setCentralWidget not working?
setCentralWidget works ok.
You are mixing up your widget menu construction with its position in an external widget (MainWindow). You should keep these thing well separated, or you won't be able, for example, to use menu inside other widgets.
So, you should set the appearance of menu in the constructor, and call setCentralWidget only in MainWindow.
It should look like:
file.h
menu::menu(QWidget* parent = 0);
file.cpp
menu::menu(QWidget* parent) : QWidget(parent)
{
// Create items
QLabel* l = new QLabel("123", this);
QLabel* ll = new QLabel("456", this);
// Put items in layout
QVBoxLayout* lay = new QVBoxLayout();
lay->addWidget(l);
lay->addWidget(ll);
// Set "lay" as the layout of this widget
setLayout(lay);
}
UPDATE
Since the wanted behavior is to have an interface that switch view according to button clicks:
the best option is to use a QStackedWidget.
Here a sample code the will produce this interface using QStackedWidget.
widget1.h
#ifndef WIDGET1
#define WIDGET1
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
class Widget1 : public QWidget
{
Q_OBJECT
public:
Widget1(QWidget* parent = 0) : QWidget(parent) {
QPushButton* btn = new QPushButton("Button Widget 1", this);
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(btn);
setLayout(layout);
connect(btn, SIGNAL(clicked()), SIGNAL(buttonClicked()));
}
signals:
void buttonClicked();
};
#endif // WIDGET1
widget2.h
#ifndef WIDGET2
#define WIDGET2
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
class Widget2 : public QWidget
{
Q_OBJECT
public:
Widget2(QWidget* parent = 0) : QWidget(parent) {
QPushButton* btn1 = new QPushButton("Button 1 Widget 2", this);
QPushButton* btn2 = new QPushButton("Button 2 Widget 2", this);
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(btn1);
layout->addWidget(btn2);
setLayout(layout);
connect(btn2, SIGNAL(clicked()), SIGNAL(button2Clicked()));
}
signals:
void button1Clicked();
void button2Clicked();
};
#endif // WIDGET2
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStackedWidget>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void buttonWidget1Clicked();
void button2Widget2Clicked();
private:
QStackedWidget* m_sw;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QVBoxLayout>
#include <QLabel>
#include "widget1.h"
#include "widget2.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// Create Widgets
Widget1* w1 = new Widget1(this);
Widget2* w2 = new Widget2(this);
QLabel* w3 = new QLabel("Result", this);
m_sw = new QStackedWidget(this);
m_sw->addWidget(w1);
m_sw->addWidget(w2);
m_sw->addWidget(w3);
setCentralWidget(m_sw);
connect(w1, SIGNAL(buttonClicked()), this, SLOT(buttonWidget1Clicked()));
connect(w2, SIGNAL(button2Clicked()), this, SLOT(button2Widget2Clicked()));
}
void MainWindow::buttonWidget1Clicked()
{
m_sw->setCurrentIndex(1); // Will show Widget2
}
void MainWindow::button2Widget2Clicked()
{
m_sw->setCurrentIndex(2); // Will show Widgee3
}
MainWindow::~MainWindow() {}