I am new to Qt. I trying convert my existing Gtk2 Project to Qt for Cross-Platform Support.
My Code as follows:
// main.cpp
int success = 0;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
success = 0;
Logon *l = new Logon();
l->show();
if(success == 1) // success flag set in Logon.cpp when connection created !
{
Menu *m = new m();
m->show();
}
return a.exec();
}
// logon.cpp
void Logon::OnOkBtnClicked(void)
{
if(!ValConnection())
return;
success = 1;
this->destroy();
}
While execute the code, the connection successfully created & the logon for disappears. But, Menu form doesn't appears.
Kindly help me to solve this.
Try to use SIGNAL/SLOT method with lambda function.
Logon .h side:
class Logon : public QObject
{
Q_OBJECT
<...>
signals:
void success(int scs);
public slots:
bool ValConnection();
}
Logon .cpp side:
// Where button creation
connect(button, &QPushButton::clicked, this, &Logon::ValConnection);
// Somewhere on ValConnection
if(true)
emit success(1);
Main side:
QObject::connect(l, &QLogon::success, [=] (int scs) {
if(scs == 1) {
Menu *m = new m();
m->show();
}
});
Related
Here is some idea of my code.It executes successfully. I am just not able to use close button the moment it starts executing read statement.!
inside main():
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
this is my constructor: one main window and a button that calls execute when clicked
inside MainWindow.cpp:
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) //this creates a window that has a download button
{
setWindowTitle("File Downloader");
QWidget* central = new QWidget(this);
QVBoxLayout *lay = new QVBoxLayout(central);
button1 = new QPushButton("Download", this);
connect(button1, SIGNAL (clicked()),this,SLOT( execute()));
lay->addWidget(button1);
manager = new QNetworkAccessManager(this);
}
this function sets up connection with php file and then calls sendFinished
void MainWindow::execute() //PHP file link here
{
QUrl url"/patofmyphp");
reply = manager->post(request, data); //data is some string
connect(reply, SIGNAL (finished()),this,SLOT( sendFinished()));
}
this function reads data from php file in chunks
void MainWindow::sendFinished() //this gets called successfully
{
while(copied < size) //copied = 0, size = 10000;
{
const QByteArray data = reply->read(tocopy);
file.write(data);
copied += data.size();
}
}
Whole program is running successfully. But when I want to abort my reply using closebutton of QMainWindow before program gets executed successfully. But the moment it reply->read gets executed, it seems close button stops working. What should I do?
Looks like I solved my issue just by using this line inside my while loop.
QApplication::processEvents(); if(close == true) { closeProgram(); }
I'm trying to create a test that will use a QNetworkAccessManager to talk with our RESTful api. All I want to do is grab a simple JSon object using a QNetworkAccessManager. My code looks like this:
Connection::Connection(QString const &username, QString const &password, QString const &url, QString const &api) :
_user(username), _pass(password), _url(url) {
_manager = new QNetworkAccessManager(this);
QObject::connect(_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveReply(QNetworkReply*)));
QNetworkRequest request;
request.setUrl(QUrl(_url.append(api)));
request.setRawHeader("Authorization", QString("Basic ").append(QString("%1:%2").arg(_user).arg(_pass)).toUtf8());
request.setHeader(QNetworkRequest::ContentTypeHeader, "text/json");
QNetworkReply *reply = _manager->get(request);
}
void Connection::Connection(QNetworkReply *reply) {
//do some validation of the reply...
_data = QJsonDocument::fromJson(reply->readAll());
}
QJsonDocument Connection::data() const {
return _data;
}
...
#include <gtest/gtest.h>
#include "Connection.h"
#include <QApplication>
TEST(ConnectionTest, creation) {
int argc = 0;
char *argv = 0;
QApplication a(argc, &argv);
Connection *connect = new Connection("user","abc123", https://mytest.com/", "api/");
connect->deleteLater();
while (connect->data().isEmpty()) {
//loop forever
}
}
Originally I was testing by having Connection also be a QWidget. The finished signal would only show if I called connection->show(); Then I have to close the widget manually and the test completes. However, this isn't really useful for automated unit testing.
If I use the above while loop to wait until _data has been set to something then nothing ever happens with the QNetworkAccessManager and it loops forever.
Is there some call that needs to happen before anything will move forward? Why was ->show() 'working?'
You're not spinning the event loop, so don't expect anything asynchronous to work at all.
You need to add a signal to the Connection class that indicates when it's done, and use that signal to quit the event loop:
TEST(ConnectionTest, creation) {
int argc = 0;
char *argv = 0;
QCoreApplication app(argc, &argv);
// No need to allocate the connection on the heap!
Connection connection("user", "abc123", "https://mytest.com/", "api/");
QObject::connect(&connection, &Connection::finished,
&app, &QCoreApplication::quit());
app.exec();
}
You could add the QApplication instance as a member of the ConnectionTest class.
There's also no need to double the number of heap allocations by having the QNetworkAccessManager * manager member. You can have it as a regular member:
class Connection : public QObject {
Q_OBJECT
QNetworkAccessManager manager;
Q_SLOT void receiveReply(QNetworkReply *) {
...
emit finished();
}
public:
explicit
Connection(const QString & user, const QString & password,
const QUrl & url, const QString & path,
QObject * parent = 0) : QObject(parent) { ... }
Q_SIGNAL void finished();
};
I'm creating a simple virtual keyboard in a QDockWidget...
When the widget is docked into the QMainWindow, the selected widget (for example a qdoublespinbox) is highlighted and if I click on the virtual keyboard clearFocus() works...
When the QDockWidget is floating above the window and I click a button, clearFocus doesn't work and I can't see the focused widget in QMainWindow...
How can I force the QDockWidget to not have any focus at all?
Thanks :-)
This is the code:
// class MyVirtualKeyboard : public QDockWidget
void MyVirtualKeyboard::sendKey(Qt::Key key, Qt::KeyboardModifier mod)
{
this->clearFocus();
QMainWindow *w = dynamic_cast<QMainWindow *>(this->parent());
if(w == NULL) return;
QWidget *widget = w->focusWidget();
QString repr = QKeySequence(key).toString();
QKeyEvent *pressEvent = new QKeyEvent(QEvent::KeyPress, key, mod, repr);
QKeyEvent *releaseEvent = new QKeyEvent(QEvent::KeyRelease, key, mod, repr);
qDebug("%s", pressEvent->text().toAscii().data());
MyApplication *app = MyApplication::myInstance();
app->postEvent(widget, pressEvent);
app->postEvent(widget, releaseEvent);
}
void MyVirtualKeyboard::on_BTN_1_clicked()
{
sendKey(Qt::Key_1);
}
...
The clearFocus() call should be unnecessary. Your dock widget and all of its widgets must have the Qt::NoFocus policy.
The code below shows how you might do it.
// https://github.com/KubaO/stackoverflown/tree/master/questions/vkb-focus-18558664
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Keyboard : public QDockWidget {
Q_OBJECT
QWidget m_widget;
QGridLayout m_layout{&m_widget};
QToolButton m_buttons[10];
void sendKey(Qt::Key key, Qt::KeyboardModifier mod)
{
if (! parentWidget()) return;
auto target = parentWidget()->focusWidget();
if (! target) return;
auto repr = QKeySequence(key).toString();
auto pressEvent = new QKeyEvent(QEvent::KeyPress, key, mod, repr);
auto releaseEvent = new QKeyEvent(QEvent::KeyRelease, key, mod, repr);
qApp->postEvent(target, pressEvent);
qApp->postEvent(target, releaseEvent);
qDebug() << repr;
}
Q_SLOT void clicked() {
auto key = sender()->property("key");
if (key.isValid()) sendKey((Qt::Key)key.toInt(), Qt::NoModifier);
}
public:
explicit Keyboard(const QString & title, QWidget *parent = nullptr) : Keyboard(parent) {
setWindowTitle(title);
}
explicit Keyboard(QWidget *parent = nullptr) : QDockWidget(parent) {
int i{};
for (auto & btn : m_buttons) {
btn.setText(QString::number(i));
btn.setProperty("key", Qt::Key_0 + i);
m_layout.addWidget(&btn, 0, i, 1, 1);
connect(&btn, SIGNAL(clicked()), SLOT(clicked()));
btn.setFocusPolicy(Qt::NoFocus);
++i;
}
setWidget(&m_widget);
setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable);
}
};
int main(int argc, char ** argv)
{
QApplication a(argc, argv);
QMainWindow w;
w.setCentralWidget(new QLineEdit);
w.addDockWidget(Qt::TopDockWidgetArea, new Keyboard("Keyboard", &w));
w.show();
return a.exec();
}
#include "main.moc"
You can prevent a widget from taking focus by setting QWidget::focusPolicy = Qt::NoFocus.
However, there are two concepts here that you're mixing - the focused control (per window), and the active window (per desktop). I think in the scenario you're describing (a torn-off popup window), the OS window manager is likely to still change the active top-level window even if Qt doesn't set a focused control. That will result in nobody having keyboard focus (which is a valid state!).
So I think a full answer to your question will involve some non-portable bits. I don't know what GUI environment you're working in, but I know some of the answer for Win32, so I'll keep going and hope that's useful:
Win32
There's a pretty good discussion of the state tracking for Win32 on MSDN in the article Win32 Activation and Focus. I'm not aware that Qt does anything to wrap this level, so you'd have to use QWidget::nativeEvent or QCoreApplication::installNativeEventFilter to get at the low-level event. If you can subclass the window, I'd prefer the former, since it's more self-contained.
bool FooWidget::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
#ifdef Q_OS_WIN
if(eventType == "windows_generic_MSG") {
const MSG *msg = reinterpret_cast<MSG *>(message);
if(msg->message == WM_MOUSEACTIVATE) {
*result = MA_NOACTIVATE;
return true;
}
}
#else
#error Need platform-specific code to suppress click-activation
#endif
return false;
}
This should block the click from activating the window (MA_NOACTIVATE), and block Qt from processing it further (return true), while leaving other all events (including the the click, since we didn't use MA_NOACTIVATEANDEAT to block it too) to be processed into QEvents and Qt signals normally (return false at the end).
If you need further low-level access (though I don't think you will), see also QWidget::effectiveWinId() and QWidget::windowHandle
Thanks a lot to Martin Gräßlin for the answer!
My recommendation: check out the virtual keyboard code in KDE Plasma: http://quickgit.kde.org/?p=kdeplasma-addons.git&a=blob&h=5628d6325afe57f85917dad865a07d4116335726&hb=a658d1e257cfca2a43c12714d026ec26f1fdb755&f=applets%2Fplasmaboard%2Fwidget.cpp
Looks like the key is setWindowFlags(Qt::X11BypassWindowManagerHint) and setFocusPolicy(Qt::NoFocus)
MyVirtualKeyboard::MyVirtualKeyboard(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::MyVirtualKeyboard)
{
ui->setupUi(this);
this->connect(this, SIGNAL(topLevelChanged(bool)), this, SLOT(topLevelChanged()));
}
void MyVirtualKeyboard::topLevelChanged()
{
if(this->isWindow())
{
this->setWindowFlags(Qt::Popup | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
this->setFocusPolicy(Qt::NoFocus);
this->show();
}
}
I think I've found a better way to do it!
Just use this->setAttribute(Qt::WA_X11DoNotAcceptFocus); and voila!
Example:
MyVirtualKeyboard::MyVirtualKeyboard(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::MyVirtualKeyboard)
{
ui->setupUi(this);
this->setAttribute(Qt::WA_X11DoNotAcceptFocus);
}
So basically what I am trying to do is the following:
I want to create a directional arrows pad on the screen. When the user presses the up or 8 key, the UI should react as if I clicked the up button. I have googled and searched all over, but as I just started using QTCreator (and C++), I am very inexperienced and any help would be appreciated.
So far I have
class GamePadWidget : public QWidget
{
public:
GamePadWidget(QWidget *parent = 0);
protected:
virtual void keyPressEvent(QKeyEvent *event);
};
GamePadWidget::GamePadWidget(QWidget *parent)
: QWidget(parent)
{
int buttonWidth = 75;
int buttonHeight = 75;
QPushButton *down = new QPushButton(("Y-"), this);;
down->setGeometry(100, 200, 100, 100);
QIcon downicon;
downicon.addFile(QString::fromUtf8("C:/arrows/Aiga_downarrow.png"), QSize(),QIcon::Normal, QIcon::Off);
down->setIcon(downicon);
down->setIconSize(QSize(buttonWidth,buttonHeight));
down->setFocusPolicy(Qt::NoFocus);
QPushButton *up = new QPushButton(("Y+"), this);;
up->setGeometry(100, 50, 100, 100);
QIcon upicon;
upicon.addFile(QString::fromUtf8("C:/arrows/Aiga_uparrow.png"), QSize(),QIcon::Normal, QIcon::Off);
up->setIcon(upicon);
up->setIconSize(QSize(buttonWidth,buttonHeight));
up->setFocusPolicy(Qt::NoFocus);
}
void GamePadWidget::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_8 || event->key() == Qt::Key_Up ) {
printf("key event in board");
}
else if (event->key() == Qt::Key_9 || event->key() == Qt::Key_Down ) {
qApp->quit();
}
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
GamePadWidget widget;
widget.show();
return app.exec();
}
with my current code, if I press down or 2, the app exits as expected, yet here is part in which I am stuck at.
I want the same functionality as if I pressed the down (or up key), the pushbutton should light up briefly then shoot off a signal to who knows where
I realize it should have something to do with connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
but cannot quite wrap my mind / find it.
Thank you for your time.
You can call a slot on an object as if it was a normal method (which it is as far as C++ is concerned). Obv you'll need to make your pushButton a member though, so you have access to it outside of the constructor.
Then yes, just connect the button's clicked() signal to the app's quit() slot. The code below should work for you (not tested though):
GamePadWidget::GamePadWidget(QWidget *parent)
: QWidget(parent)
{
...
mDownButton = new QPushButton(("Y-"), this);;
...
connect(mDownButton, SIGNAL(clicked()), qApp, SLOT(quit()));
}
void GamePadWidget::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Down ) {
qDebug() << "Down key pressed";
mDownButton.click();
}
}
I am new to QT and I am doing some learning.
I would like to trigger a slot that modify a GUI widget from a C++ thread(Currently a Qthread).
Unfortunatly I get a: ASSERTION failed at: Q_ASSERT(qApp && qApp->thread() == QThread::currentThread());
here is some code:
(MAIN + Thread class)
class mythread : public QThread
{
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
w->ui.textEdit->append("Hello"); //<--ASSERT FAIL
//I have also try to call a slots within mywindow which also fail.
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
thr->start();
return a->exec();
}
Window:
class mywindow : public QMainWindow
{
Q_OBJECT
public:
mywindow (QWidget *parent = 0, Qt::WFlags flags = 0);
~mywindow ();
Ui::mywindow ui;
private:
public slots:
void newLog(QString &log);
};
So I am curious on how to update the gui part by code in a different thread.
Thanks for helping
stribika got it almost right:
QMetaObject::invokeMethod( textEdit, "append", Qt::QueuedConnection,
Q_ARG( QString, myString ) );
cjhuitt's right, though: You usually want to declare a signal on the thread and connect it to the append() slot, to get object lifetime management for free (well, for the price of a minor interface change). On a sidenote, the additional argument:
Qt::QueuedConnection ); // <-- This option is important!
from cjhuitt's answer isn't necessary anymore (it was, in Qt <= 4.1), since connect() defaults to Qt::AutoConnection which now (Qt >= 4.2) does the right thing and switches between queued and direct connection mode based on QThread::currentThread() and the thread affinity of the receiver QObject at emit time (instead of sender and receiver affinity at connect time).
In addition to stribika's answer, I often find it easier to use a signal/slot connection. You can specify that it should be a queued connection when you connect it, to avoid problems with the thread's signals being in the context of its owning object.
class mythread : public QThread
{
signals:
void appendText( QString );
public:
mythread(mywindow* win){this->w = win;};
mywindow* w;
void run()
{
emit ( appendText( "Hello" ) );
};
};
int main(int argc, char *argv[])
{
QApplication* a = new QApplication(argc, argv);
mywindow* w = new mywindow();
w->show();
mythread* thr = new mythread(w);
(void)connect( thr, SIGNAL( appendText( QString ) ),
w->ui.textEdit, SLOT( append( QString ) ),
Qt::QueuedConnection ); // <-- This option is important!
thr->start();
return a->exec();
}
You need to use QMetaObject::invokeMethod. For example:
void MyThread::run() {
QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello"));
}
(The above code comes from here: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)
I don't think you are allowed to call directly things that results in paint events from any
other threads than the main thread. That will result in a crash.
I think you can use the event loop to call things asynchronously so that the main gui thread picks up and then does the updating from the main thread, which is what cjhuitt suggests.