My QDialog is causing a seg fault after it closes. I malloc my struct before using it, settings is of type PSETTINGS and is a private variable.
MainWindow Class:(Seg Fault happens in settingsDiag->exec())
Settings *settingsDiag = new Settings(this);
settingsDiag->exec();
Settings Class:
In header file:
typedef struct ConnSettings {
ConnSettings():ipAddr(""), alias("Local"), port(8000), isClient(false){}
QString ipAddr;
QString alias;
int port;
bool isClient;
} SETTINGS, *PSETTINGS;
In CPP file:
Settings::Settings(QWidget *parent) :
QDialog(parent),
ui(new Ui::Settings)
{
ui->setupUi(this);
QButtonGroup serviceGroup(ui->serviceBox);
QValidator *validPort = new QRegExpValidator(QRegExp("^\\d*$"), this);
QValidator *validIp = new QRegExpValidator(QRegExp("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$"), this);
serviceGroup.addButton(ui->clientButton);
serviceGroup.addButton(ui->serverButton);
connect(ui->okCancel, SIGNAL(accepted()), this, SLOT(storeSettings()));
connect(ui->clientButton, SIGNAL(toggled(bool)), this, SLOT(enableDisableClient(bool)));
ui->portText->setValidator(validPort);
ui->ipText->setValidator(validIp);
}
Settings::~Settings() {
delete ui;
}
void Settings::storeSettings() {
settings = (PSETTINGS)malloc(sizeof(SETTINGS));
settings->port = ui->portText->text().toInt();
if((settings->isClient = ui->clientButton->isChecked())) {
settings->ipAddr = ui->ipText->text();
settings->alias = ui->aliasText->text();
}
}
PSETTINGS Settings::getSettings() {
return settings;
}
void Settings::enableDisableClient(bool client) {
ui->clientBox->setEnabled(client);
}
Thanks :)
The malloc is causing problems too. The strings in that struct get used without being constructed. Assume your heap corrupted after that point.
Instead of malloc try...
settings = new SETTINGS();
... and of course delete when you are done with it.
You are allocating the QButtonGroup serviceGroup on the stack. Probably not what you want to do.
Related
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();
}
});
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);
}
i have a problem with a small program (I am a beginner with c++ and qt).
On button press it starts a cli application with qprocess and the output should be displayed in a text field as soon as the cli app writes it to stdout or stderr.
i read that its a good idea to use signals and slots for this but it isnt working.
the compiler throws an error that in my slot getOutput() the "process" object isn't declared (C2065)
here is the code.
processgui.cpp:
#include "processgui.h"
#include "ui_processgui.h"
#include <QProcess>
processGui::processGui(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::processGui)
{
ui->setupUi(this);
}
processGui::~processGui()
{
delete ui;
}
void processGui::on_startProcess_clicked() {
QProcess *process = new QProcess(this);
QString program = "tracert";
QString arguments = "";
process->setReadChannelMode(QProcess::MergedChannels);
process->start(program, QStringList() << arguments);
process->waitForStarted();
QObject::connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(getOutput()));
}
void processGui::getOutput() {
QByteArray strdata = process->readAllStandardOutput();
ui->textLog->append(strdata);
}
processgui.h :
#ifndef PROCESSGUI_H
#define PROCESSGUI_H
#include <QMainWindow>
namespace Ui {
class processGui;
}
class processGui : public QMainWindow
{
Q_OBJECT
public:
explicit processGui(QWidget *parent = 0);
~processGui();
private slots:
void on_startProcess_clicked();
void getOutput();
private:
Ui::processGui *ui;
};
#endif // PROCESSGUI_H
thanks in advance
Move QProcess *process to your header and initialize it with process = new QProcess(this) in your constructor. That way you can access it in your slot.
QProcess *process = new QProcess(this);
is declared in:
void processGui::on_startProcess_clicked()
it's a scope problem, process is a local variable not available in the whole class.
You can access QProcess object inside a slot with sender(), like this:
void processGui::getOutput()
{
QProcess* process = qobject_cast<QProcess*>(sender());
QByteArray strdata = process->readAllStandardOutput();
}
For my GUI i would like to have two pairs of buttons that scroll up and down a scrollarea. The first set of buttons should work on say scrollarea1 and the second set of buttons should work on a scrollarea2. The widgets that I put in the scrollarea are called viewport1 and viewport2.
Since both both set of buttons should do the same (scrolling up and down) I thought I would make two slots called scrollUp and scrollDown that would handle the scrolling for both sets of buttons. Unfortunately I cannot make this work and need some help. I have tried the following:
QPushButton up;
QPushButton down;
QPushButton up2;
QPushButton down2;
connect(&up,SIGNAL(clicked()),&up,SLOT(scrollUp()));
connect(&up2,SIGNAL(clicked()),&up,SLOT(scrollUp()));
connect(&down,SIGNAL(clicked()),&down,SLOT(scrollDown()));
connect(&down2,SIGNAL(clicked()),&down,SLOT(scrollDown()));
void MainWindow::scrollDown()
{
QScrollArea area;
QWidget view;
if((QPushButton) &sender = down)
{
area=scrollArea;
view=viewport;
}
if((QPushButton) &sender = down2)
{
area=scrollArea;
view=viewport;
}
int curpos = area.verticalScrollBar()->value();
area.verticalScrollBar()->setValue(curpos+15);
int newpos = area.verticalScrollBar()->value();
QPoint topLeft = area.viewport()->rect().topLeft();
view.move(topLeft.x(),topLeft.y()-(newpos));
}
void MainWindow::scrollUp()
{
QScrollArea area;
QWidget view;
if((QPushButton) &sender = up)
{
area=scrollArea;
view=viewport;
}
if((QPushButton) &sender = up2)
{
area=scrollArea2;
view=viewport2;
}
int curpos = area.verticalScrollBar()->value();
area.verticalScrollBar()->setValue(curpos-15);
int newpos = area.verticalScrollBar()->value();
QPoint topLeft = area.viewport()->rect().topLeft();
view.move(topLeft.x(),topLeft.y()-(newpos));
}
But this doesn´t work for several reasons. I also tried giving the slot some arguments, something like:
connect(&up,SIGNAL(clicked()),&up,SLOT(scrollUp(scrollarea1,viewport1)));
connect(&up2,SIGNAL(clicked()),&up,SLOT(scrollUp(scrollarea2,viewport2)));
But again, no succes. Can anybody help me?
First of all, "It doesn't work" does not mean anything, and it is hard to help you if you do not say what errors you get. Then, there are few problems.
All QObject's derived classes are not copiable, it means you can not do
QWidget a;
QWidget b;
b = a; // Wrong
You should use pointers (or perhaps references).
QWidget a;
QWidget * b = new QWidget(...);
QWidget * c;
c = & a; // Ok
c = b; // Ok
Then your connect calls are wrong:
connect(&up, SIGNAL(clicked()), &up, SLOT(scrollUp()));
The third argument is the object who has the slot. up is a QPushButton, it does not have a scrollUp() slot, it is your MainWindow who does:
connect(&up, SIGNAL(clicked()), this, SLOT(scrollUp()));
(since connect is called in MainWindow's constructor this points to the current MainWindow object).
Also in C++ the single = sign means assignment, for equality comparison use =='. Andsender` is a function.
Your approach should work if implemented in the right way:
class MainWindow: public QWidget
{
QScrollArea * scroll1;
QScrollArea * scroll2;
QWidget * view1;
QWidget * view2;
QPushButton * up1;
QPushButton * up2;
QPushButton * down1;
QPushButton * down2;
public:
MainWindow()
{
// Here initialize member variables.
...
connect(up1, SIGNAL(clicked()), this, SLOT(scrollUp()));
connect(up2, SIGNAL(clicked()), this, SLOT(scrollUp()));
connect(down1, SIGNAL(clicked()), this, SLOT(scrollDown()));
connect(down2, SIGNAL(clicked()), this, SLOT(scrollDown()));
}
public slots:
void scrollDown()
{
QScrollArea * area;
QWidget * view;
if(qobject_cast<QPushButton>(sender()) == down1) {
area = & scroll1;
view = & view1;
} else if(qobject_cast<QPushButton>(sender()) == down2) {
area = & scroll2;
view = & view2;
} else {
// Error.
}
// Now `area` and `view` point to the right widgets.
...
}
void scrollUp()
{
// The same as before.
}
};
Another approach would be to extract the actual scrolling instructions to a separate function:
class MainWindow: public QWidget
{
// Same variables as before
...
public:
MainWindow()
{
// Here initialize member variables.
...
connect(up1, SIGNAL(clicked()), this, SLOT(scrollUp1()));
connect(up2, SIGNAL(clicked()), this, SLOT(scrollUp2()));
connect(down1, SIGNAL(clicked()), this, SLOT(scrollDown1()));
connect(down2, SIGNAL(clicked()), this, SLOT(scrollDown2()));
}
public slots:
void scrollDown(QScrollArea * area, QWidget * view)
{
// Here you scroll over `area` and `view`.
}
void scrollDown1()
{
scrollDown(scroll1, area1);
}
void scrollDown2()
{
scrollDown(scroll2, area2);
}
// Again, the same for `scrollUp`.
};
There are several mistakes in your code :
About the sender of the signal : There is not a QObject called "sender" but a method QObject * QObject::sender() const; which returns a pointer on the sender of the signal.
In the if conditions : you are casting a QPushButton** into a QPushButton ((QPushButton) &sender) and you dont compare that thing with your buttons up(2) and down(2).
In your connections between slots and signals : the scrollUp and scrollDown slots do not belong to the QPushButton class but to your MainWindow class.
Finally, you should write something like this :
connect(&up, SIGNAL(clicked()), this, SLOT(scrollUp()));
connect(&up2, SIGNAL(clicked()), this, SLOT(scrollUp()));
connect(&down, SIGNAL(clicked()), this, SLOT(scrollDown()));
connect(&down2, SIGNAL(clicked()), this, SLOT(scrollDown()));
void MainVindow::scrollDown() {
// [...]
QPushButton * senderButton = qobject_cast<QPushButton *>(this->sender());
// QPushButton * senderButton = (QPushButton *) this->sender(); works too
if (senderButton == &down) {
// [...]
}
if (senderButton == &down2) {
// [...]
}
// [...]
}
void MainVindow::scrollUp() {
// [...]
QPushButton * senderButton = qobject_cast<QPushButton *>(this->sender());
// QPushButton * senderButton = (QPushButton *) this->sender(); works too
if (senderButton == &up) {
// [...]
}
if (senderButton == &up2) {
// [...]
}
// [...]
}
First of all the slot can have no other arguments than the signal hands to it. Clicked has no arguments and there fore the slot can have no arguments.
I would think that the easiest way to check whether scrollArea 1 or 2 has focus and decide from that which one should move.
I also think that there is an error in your code. Shouldn't this:
if((QPushButton) &sender = down2)
{
area=scrollArea;
view=viewport;
}
Be this:
if((QPushButton) &sender = down2)
{
area=scrollArea2;
view=viewport2;
}
First of all, this is pseudo code. It won't compile, but it should contain the necessary information.
I believe this problem can be most elegantly solved using the QSignalMapper class. It allows parameterless signals from multiple senders to connect to one slot.
In the header, write something like this:
class QSignalMapper;
class MainWindow : public QMainWindow
{
public:
void init();
public slots:
void handleScrollButtons(int id);
private:
enum { ScrollUp1, ScrollDown1, ScrollUp2, ScrollDown2 } // just makes it more convenient to use
QSignalMapper *m_scrollbuttonhandler;
}
In the source file, write something like this
#include <QSignalMapper>
void MainWindow::init()
{
m_scrollbuttonhandler = new QSignalMapper(this);
m_scrollbuttonhandler->setMapping(scrollup1button, ScrollUp1);
m_scrollbuttonhandler->setMapping(scrolldown1button, ScrollDown1);
m_scrollbuttonhandler->setMapping(scrollup2button, ScrollUp2);
m_scrollbuttonhandler->setMapping(scrolldown2button, ScrollDown2);
connect(scrollup1button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
connect(scrolldown1button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
connect(scrollup2button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
connect(scrolldown2button, SIGNAL(clicked(bool)), m_scrollbuttonhandler, SLOT(map()));
connect(m_scrollbuttonhandler, SIGNAL(mapped(int)), this, SLOT(handleScrollButtons(int)));
}
void MainWindow::handleScrollButtons(int id)
{
switch (id)
{
case ScrollUp1:
// stuff to do for scrollup1button
case ScrollDown1:
// stuff to do for scrolldown1button
case ScrollUp2:
// stuff to do for scrollup2button
case ScrollDown2:
// stuff to do for scrolldown2button
}
}
I would like to know which of the following is the proper way of doing thing with signal/slot in Qt.
I need a way to have multiple instance of a Dialog, i.e: A and B. And I need to tell A to print "A" and B to print "B" from a different thread. So I believe I need something like either:
OPTION 1) A->print("A") and B->print("B")
or is it better to do:
OPTION 2) emit print("A") and emit print("B") and use a way that I don't know so only A catch the "A" and only B catch the "B".
I got the option 1 working like this:
class myClass : public QMainWindow
{
Q_OBJECT
public:
myClass (QWidget *parent = 0, Qt::WFlags flags = 0);
~myClass ();
void doPrint(char* text)
{
emit mySignal(text);
}
private:
Ui::myClass ui;
public slots:
void newLog(char* msg);
signals:
void mySignal(char* msg);
};
myClass::myClass(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
ui.setupUi(this);
connect(this, SIGNAL(mySignal(char*)), this, SLOT(newLog(char*)));
}
void myClass::newLog(char* msg)
{
ui.textEdit->append(msg);
}
and then all I have to do is:
myClass* instanceA = new myClass();
myClass* instanceB = new myClass();
instanceA->doPrint("A");
instanceB->doPrint("B");
is this right?
Thanks!
Since your slot is in another thread, you have to use the Meta-Object System to invoke the method asynchronously. The proper way to do this is to use QMetaObject::invokeMethod
DO NOT subclass QThread and override the run method. For details on this see: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
void otherClass::printTo(myClass* instance, char* text)
{
QMetaObject::invokeMethod(instance, // pointer to a QObject
"doPrint", // member name (no parameters here)
Qt::QueuedConnection, // connection type
Q_ARG(char*, text)); // parameters
}
void myClass::doPrint(char* text)
{
ui.textEdit->append(text);
}
myClass* instanceA = new myClass();
myClass* instanceB = new myClass();
printTo(instanceA, "A");
printTo(instanceB, "B");
If the char* type hasn't been registered with the Meta-Object System yet, do so with
Q_DECLARE_METATYPE(char*);
then:
qRegisterMetaType<char*>("charPtr");
In this simplified example, I think you are on the correct path with option 1. However, it would be even better if you didn't need the doPrint() method, which would also eliminate the need for the mySignal signal (at least in myClass). Instead, I would suggest inheriting your threads from QThread if the aren't already, and doing something like this:
class myThread : public QThread
{
Q_OBJECT
public:
myThread (QWidget *parent = 0 ) : QThread(parent) {}
~myThread () {}
void run(char* text)
{
emit mySignal(text);
}
signals:
void mySignal(char* msg);
};
Then you need to do something like this:
myClass* instanceA = new myClass();
myThread* threadA = new myThread();
connect(threadA, SIGNAL(mySignal(char*)), instanceA, SLOT(newLog(char*)), Qt::QueuedConnection);
threadA->run( "A" );
Obviously, in most non-example code, you'd not pass the string into run, but rather generate strings to be run as threadA is running. The advantage is that this keeps the thread considerations out of myClass, and you only need to think about them where they are connected. On the flip side, you introduce fewer dependencies into the threads, since they don't need to know about myClass to be able to log.