Why virtual keyboard does not work with QDialog textbox in Qt? - c++

I make an application for keyboard less device.
I used thisRef for keyboard as virtual keyboard.
I have a dialog in my project that has two textboxes (one of them for enter user name and the other for input password ) with two buttons: OK and Cancel. after Build the project and run ,the press menu button to show menu form, then the dialog appears to check user authenticate. the user should enter data on text box the virtual keyboard .
the virtual keyboard (input panel in thisRef ) appears but the buttons not work.
when I searched I saw this "sounds like you are trying to open another window from the dialog - this is your error. Of course the dialog will stay on top - that is its job."
because the dialog is modal, the virtual keyboard is disable
Is there anyway to edit the dialog or keyboard to work in modal widget?
main.cpp
#include "mainwindow.h"
#include <QApplication>
#include "myinputpanelcontext.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyInputPanelContext *ic= new MyInputPanelContext; ;
a.setInputContext(ic);
MainWindow w;
//w.show();
w.showFullScreen();
w.centralWidget()->releaseKeyboard();
return a.exec();
}
MainWindow.cpp:
MyDialog *d=new MyDialog(this);
d.exec();

It solved:
Modal dialogs are started with exec(), they block the program flow while a nested event loop runs.
Modeless dialogs are started with show(), they do not block the program flow.
From http://www.qtforum.org/article/14285/modeless-dialog.html
I use this code :
MyDialog *d=new MyDialog(this);
d->show();
d->raise();
q->activewindows();
instead of this code:
MyDialog *d=new MyDialog(this);
d.exec();
as the document reference :
A modeless dialog: void EditorWindow::find() {
if (!findDialog) {
> findDialog = new FindDialog(this);
> connect(findDialog, SIGNAL(findNext()), this, SLOT(findNext()));
> } findDialog->show();
> findDialog->raise();
> findDialog->activateWindow(); }
From here

Related

Qt Auto-UI Testing stopping because of messagebox. How to simulate enter on messagebox?

My task is to write an automated UI test for a software being developed. It happens so, that there are radiobuttons triggering a messagebox, which stops my automated test until I manually confirm it (pressing ENTER). The issue is that I do not know how I can call that newly summoned messagebox and then have it confirmed by QTest::keyClick(<object>, QtKey::Key_Enter); and have my automated test continue the run.
I am using QWidgets, QApplication, Q_OBJECT and QtTest.
I will provide a code similar to what I am working with:
void testui1(){
Form1* myform = new Form1();
myform->show();
QTest::mouseClick(myform->radioButton01, Qt::LeftButton, Qt::NoModifier, QPoint(), 100);
// Message box pops up and stops the operation until confirmed
QTest::mouseClick(myform->radioButton02, Qt::LeftButton, Qt::NoModifier, QPoint(), 100);
// again
...
}
How exactly can I script to confirm the message box automatically? The message box is only an [OK] type, so I don't need it to return whether I have pressed Yes or No. A QTest::keyClick(<target object>, Qt::Key_Enter) method needs to know to which object it should press enter to. I tried including myform into the object and it did not work. Googling I did not find the answer. I found the following result as not functioning for what I am looking for
QWidgetList allToplevelWidgets = QApplication::topLevelWidgets();
foreach (QWidget *w, allToplevelWidgets) {
if (w->inherits("QMessageBox")) {
QMessageBox *mb = qobject_cast<QMessageBox *>(w);
QTest::keyClick(mb, Qt::Key_Enter);
}
}
The problem is that once you've "clicked" on your radio button, which results in QMessageBox::exec being called, your code stops running until the user clicks on of the buttons.
You can simulate the user clicking a button by starting a timer before you click on the radio button.
In the callback function for the timer you can use QApplication::activeModalWidget() to obtain a pointer to the message box, and then just call close on it.
QTimer::singleShot(0, [=]()
{
QWidget* widget = QApplication::activeModalWidget();
if (widget)
widget->close();
});
If you want to press a specific key on the message box, you can use QCoreApplication::postEvent to post a key event to the message box
QTimer::singleShot(0, [=]()
{
int key = Qt::Key_Enter; // or whatever key you want
QWidget* widget = QApplication::activeModalWidget();
if (widget)
{
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
QCoreApplication::postEvent(widget, event);
}
});
So in terms of how this ties into the sample code you gave:
void testui1()
{
Form1* myform = new Form1();
myform->show();
QTimer::singleShot(0, [=]()
{
QWidget* widget = QApplication::activeModalWidget();
if (widget)
widget->close();
else
QFAIL("no modal widget");
});
QTest::mouseClick(myform->radioButton01, Qt::LeftButton, Qt::NoModifier, QPoint(), 100);
}
A sample app putting all the above together:
#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTimer>
#include <QMessageBox>
#include <iostream>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QMainWindow window;
QWidget widget;
window.setCentralWidget(&widget);
QHBoxLayout layout(&widget);
QPushButton btn("go");
layout.addWidget(&btn);
QObject::connect(&btn, &QPushButton::clicked, [&]()
{
QTimer::singleShot(0, [=]()
{
QWidget* widget = QApplication::activeModalWidget();
if (widget)
{
widget->close();
}
else
{
std::cout << "no active modal\n";
}
});
QMessageBox(
QMessageBox::Icon::Warning,
"Are you sure?",
"Are you sure?",
QMessageBox::Yes | QMessageBox::No,
&window).exec();
});
window.show();
return app.exec();
}
Clicking on Go will look like nothing is happening, as the QMessageBox is closed immediately.
To prove that the message box is shown and then closed you can increase the time in the call to QTimer::singleShot to a value such as 1000. Now it will show the message box for 1 second, and then it will be closed by the timer.

How can I program a custom popup Window in Qt?

My Qt application consists of several screens added on a QStackedLayout(). Now after some useraction I would like a little popup window that confirms the action and disappears after a few seconds. What I would like is a gray rectangle with black border and some text in it. No buttons, no titlebar.
I tried to do it with QMessage Box (see code below) but in general it doesnt seem to be possible to adjust border styles for QMessageBox(). Also the size can't be adjusted.
QMessageBox* tempbox = new QMessageBox;
tempbox->setWindowFlags(Qt::FramelessWindowHint); //removes titlebar
tempbox->setStandardButtons(0); //removes button
tempbox->setText("Some text");
tempbox->setFixedSize(800,300); //has no effect
tempbox->show();
QTimer::singleShot(2000, tempbox, SLOT(close())); //closes box after 2 seconds
So, how can I program a custom popup Window in Qt?
First of all, I'd like to recommend the Windows Flags Example of the Qt docs. It provides a nice sample to play around with this topic. In this sample, a QWidget is derived to show the effect of the distinct flags. This brought me to the idea that probably any QWidget can be used for this if the appropriate Qt::WindowFlags are set. I choosed QLabel because
it can display text
it inherits from QFrame and, thus, can have a frame.
Source code testQPopup.cc:
// standard C++ header:
#include <iostream>
#include <string>
// Qt header:
#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QTimer>
using namespace std;
int main(int argc, char **argv)
{
cout << QT_VERSION_STR << endl;
// main application
#undef qApp // undef macro qApp out of the way
QApplication qApp(argc, argv);
// setup GUI
QMainWindow qWin;
qWin.setFixedSize(640, 400);
qWin.show();
// setup popup
QLabel qPopup(QString::fromLatin1("Some text"),
&qWin,
Qt::SplashScreen | Qt::WindowStaysOnTopHint);
QPalette qPalette = qPopup.palette();
qPalette.setBrush(QPalette::Background, QColor(0xff, 0xe0, 0xc0));
qPopup.setPalette(qPalette);
qPopup.setFrameStyle(QLabel::Raised | QLabel::Panel);
qPopup.setAlignment(Qt::AlignCenter);
qPopup.setFixedSize(320, 200);
qPopup.show();
// setup timer
QTimer::singleShot(1000,
[&qPopup]() {
qPopup.setText(QString::fromLatin1("Closing in 3 s"));
});
QTimer::singleShot(2000,
[&qPopup]() {
qPopup.setText(QString::fromLatin1("Closing in 2 s"));
});
QTimer::singleShot(3000,
[&qPopup]() {
qPopup.setText(QString::fromLatin1("Closing in 1 s"));
});
QTimer::singleShot(4000, &qPopup, &QLabel::hide);
// run application
return qApp.exec();
}
I compiled with VS2013 and Qt 5.6 on Windows 10 (64 bit). The image below shows a snaphot:
To make the popup better visible (and because I liked it), I changed the background color of the QLabel for popup. And, I couldn't resist to add a little countdown.

How to close the main window when a dialog appears

I was making a test program where the MainWindow serves as a login screen. User types in a username and password. If they match what the string is assigned to, then the Dialog appears. If it fails, a QMessageBox appears instead.
What my issue is when I want the Dialog to appear (the main program), I want the Login page to disappear. The Command close(); would just close everything.
Here is the code for the MainWindow.cpp (The Dialog is referenced in the header as a POINTER called mDialog)
void MainWindow::on_pushButton_clicked()
{
if (ui->lineEdit->text() == username)
{
if (ui->lineEdit_2->text() == password)
{
//This is where the Dialog appears
mDialog= new MyDialog(this);
mDialog->show();
}
}
else if (ui->lineEdit->text() != username || ui->lineEdit->text() ==NULL)
{
if (ui->lineEdit_2->text() != password || ui->lineEdit_2->text() == NULL)
{
QMessageBox::warning(this, "Error", "The username or password is incorrect.");
}
}
}
Here is the code for the main.cpp
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
In Qt if the parent is destroyed, the children also, so if you go to this as a parameter to MyDialog, it will be destroyed. So that it is not destroyed do not pass the parent.
Change mDialog= new MyDialog(this) to mDialog= new MyDialog() and place close() after show().
The function would look like:
...
mDialog= new QDialog();
mDialog->show();
close();
...
I think you should be showing the dialog as the login and the main window as the main program. If login is a success, show main window, not the other way around. Closing the main window is going to close the program.
I have done what you are trying to do. You can do what I said above or another option is to create a login screen in the main window using a QLabel. You can add an image to the Qlabel (a solid color image or anything you like) and make it the size of the window to block the view of the main program. Then you can add your line edits and buttons or anything you want. If login is successful, the image, labels and buttons can be closed to reveal the main program. I checked input using regular expressions.
Use this->close() to close the current window, but in the constructor of MyDialog, don't pass anything to the constructor. By default, the constructor will pass 0 to the parent argument, so as a result, the dialog will not have a parent.
If your main program is the Dialog you can before it have been shown open the login dialog with username/password fields.
Pseudocode for the main function (LoginDialog and MainDialog inherits QDialog):
QApplication a(argc, argv);
LoginDialog lDialog;
lDialog.exec(); // Modal dialog behavior. Stopped at this line while it not closed (QDialog::close())
if (lDialog.getUsername() != username || lDialog.getPassword() != password)
{
return 0;
}
MainDialog mDialog;
mDialog.show();
return a.exec();
You can set window visibility to false.
mainwindow.setVisible(false)

Maximize window maintaining taskbar limits

I want to create a Qt application without the windows title bar (I want to create a customized one).
I've created three buttons for minimizing, maximizing and closing the window. Everything works except for considering that when I maximize the window, application doesn't take into account the taskbar, and the maximized window takes the entire screen, going under the taskbar. A normal maximize command from windows instead maximizes the application window avoiding to go under the taskbar.
If I don't use the Qt::CustomizeWindowHint the window title bar appears, and maximizing behaviour is correct; but if I use this flag, the title bar disappears and the application goes under the window: here you can find two screenshots explaning the behaviour:
With Windows title:
Without Windows title:
As you can see in latter case che "Close" button goes inside the taskbar because the application takes the entire screen.
How can I avoid this behaviour without using windows title bar? I want to recreate the same behaviour as with the window title bar.
SampleWindow.h
#ifndef SAMPLEWINDOW_H_
#define SAMPLEWINDOW_H_
#include <QMainWindow>
#include <QPushButton>
#include <QHBoxLayout>
class SampleWindow : public QMainWindow {
Q_OBJECT
public:
SampleWindow();
virtual ~SampleWindow() = default;
};
#endif // !SAMPLEWINDOW_H_
SampleWindow.cpp
#include "SampleWindow.h"
#include <QCoreApplication>
SampleWindow::SampleWindow() :
QMainWindow() {
// With uncommenting this line the title bar disappears
// but application goes under the taskbar when maximized
//
//setWindowFlags(Qt::CustomizeWindowHint);
auto centralWidget = new QWidget(this);
auto layout = new QHBoxLayout(this);
auto minimizeButton = new QPushButton("Minimize", this);
auto maximizeButton = new QPushButton("Maximize", this);
auto closeButton = new QPushButton("Close", this);
layout->addWidget(minimizeButton);
layout->addWidget(maximizeButton);
layout->addWidget(closeButton);
centralWidget->setLayout(layout);
setCentralWidget(centralWidget);
connect(closeButton, &QPushButton::clicked, [=]() {QCoreApplication::quit();});
connect(minimizeButton, &QPushButton::clicked, this, [=]() {setWindowState(Qt::WindowMinimized);});
connect(maximizeButton, &QPushButton::clicked, this, [=]() {setWindowState(Qt::WindowMaximized);});
}
Main.cpp
#include <QApplication>
#include "SampleWindow.h"
int main(int argc, char* argv[]) {
QApplication app(argc, argv);
SampleWindow mainWindow;
mainWindow.show();
return app.exec();
}
This behavior depends on system. I tested your code on Windows 7 and Linux Mint KDE and behavior was different. In Windows 7 taskbar has hidden and window has filled area of taskbar. In KDE I have noticed that window maximizes correctly (avoids widget panels and not hides them).
However when I try to run code in Windows 10 with compatibility mode, I was able to repeat behavior of Win7 only in compatibility with Windows Vista and older versions.
For Windows 10 I found another solution: you can maximize your window in fullscreen if that suits you:
mainWindow.showFullScreen();
or
setWindowState(Qt::WindowFullScreen);
UPD:
In addition to your solution I found another one:
setGeometry(QApplication::desktop()->availableGeometry().x(),
QApplication::desktop()->availableGeometry().y(),
QApplication::desktop()->availableGeometry().width(),
QApplication::desktop()->availableGeometry().height());
I think that I've found a solution by using this slot when maximize button is clicked:
void SampleWindow::maximize() {
//setWindowState(Qt::WindowFullScreen);
QDesktopWidget *desktop = QApplication::desktop();
QRect desktopGeometry = desktop->availableGeometry();
int desktopHeight = desktopGeometry.height();
int desktopWidth = desktopGeometry.width();
int padx = (frameGeometry().width() - geometry().width()) / 2;
setFixedSize(desktopWidth, desktopHeight);
move(-padx,0);
}
I need to test it more but at the moment the area seems correct.

How to set focus on QMenu Item programmatically

What I want to do with this piece of code is set the focus on the QMenu Item programmatically. But neither QMenu::setActiveAction() nor QMenu::popup() works.
How can I do that?
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow *window = new QMainWindow();
window->setWindowTitle(QString::fromUtf8("Test:QMenu"));
window->resize(336, 227);
QAction *newAct = new QAction("&New",window);
QAction *openAct = new QAction("&Open",window);
QAction *saveAct = new QAction("&Save",window);
QMenu *fileMenu;
fileMenu = window->menuBar()->addMenu("&File");
fileMenu->addAction(newAct);
fileMenu->addAction(openAct);
fileMenu->addAction(saveAct);
window->show();
fileMenu->popup(QPoint(10,10));
return app.exec();
}
QMenu items are not "focusable" in the same manner as other widgets. And, actually, they shouldn't, because what you want is not common practice of their usage.
As a workaround, on mouse press you can get mouse cursor position, pre-calculate offset of your default menu item in the popup menu and show the menu at the point, where mouse cursor underly your default menu item. This solution was suggested here.
Also, what will be more nice for user, to select default menu item you can generates narrow keys buttons events after you display your popup. This works on Windows, but not sure about other OS.