I'm new in QT. Could someone help me with this?
I'm coding a widget application (with QMainWindow) with three QLineEdits widgets, I used setText to set a random text and connect the timeout() signal to a slot. When the timer "interrupts" I want to know in which QLineEdit the cursor is.
MainWindow constructor:
ui->setupUi(this);
timer = new QTimer(this);
timer -> start(1000); // 1 sec
connect(timer, SIGNAL(timeout()), this, SLOT(FinishTimer()));
ui->lineEdit1->setText("Line1");
ui->lineEdit2->setText("Line2");
ui->lineEdit1->setFocus();
In finish timer function I want to move the cursor but first I need to know in wich QLineEdit I am and the position of the cursor.
FinishTimer slot:
QString debug;
debug = this->focusWidget()->objectName(); //this is a debug line, it works fine
// this line doesn't work
int position = this->focusWidget()->cursorPosition();
cursorPosition it's a method of QLineEdit, the error is "class QWidget has no member named 'cursorPosition'". I hope you will understand me.
I used qobject_cast and it works really well. Thanks
position=qobject_cast<QLineEdit*>(this->focusWidget())->cursorPosition();
Related
I have implemented a QTreeview with QAbstractItemModel how can i be notified if i click on the tree view item with left mouse click.Do we have any function like OnLButtonDown() avalible for the tree view.
WavefrontRenderer::WavefrontRenderer(TreeModel* model , QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
treeView->setModel(model);
treeView->setDragEnabled(true);
treeView->setAcceptDrops(true);
treeView->installEventFilter(this);
connect(pushButtonAddGroup, SIGNAL(clicked()), this, SLOT(insertRow()));
connect(pushButtonAddChild , SIGNAL(clicked()), this,
SLOT(insertChild()));
connect(pushButtonDeleteGroup , SIGNAL(clicked()), this,
SLOT(removeRow()));
connect( ButtonSphere, SIGNAL(clicked()), this, SLOT(AddSphere()));
connect(treeView , SIGNAL(clicked()), this, SLOT(message()));
}
I tried to connect the treeview to clicked slot but this did not work for me.
Since i am new to qt i am not sure if we connect the treeview same way as we connect buttons to the clicked slots.
You should always check your connections:
bool ok = connect(...);
Q_ASSERT(ok);
If you do that, you'll find that connecting to the clicked() signal doesn't work.
If you then take a look at your error console you'll see a Qt message that the signal clicked() is not found in QTreeView.
That's because the parameters need to be included in the SIGNAL(...) macro.
Either put them there but just the type without the parameter name:
bool ok = connect(treeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(message()));
or avoid this pitfall by using the new connect syntax:
bool ok = connect(treeView, &QAbstractItemView::clicked, this, &WavefrontRenderer::message);
This will give you a compiler error if the signal or slot doesn't exist.
I need to process and close QFileDialog in tests of the application.
The dialog invoked by:
QFileDialog::getOpenFileName( ... );
In the test I 'catch' this dialog by:
QApplication::topLevelWidgets();
Then I choose need file by QFileDialog API.
And now I should close the dialog to get valid answer (filename) from QFileDialog::getOpenFileName();
But QDilaog's slots has no effect (accept(), reject(), close()... ). The dialog stays opened.
The solution described here works, but it is no option in my case. I must to use standard dialogs.
Is there a way to close it properly?
QFileDialog::getOpenFileName is a static method, so you're limited by what you can do with it.
If you want more control, I suggest creating an instance of QFileDialog and using that instead. By calling the instance's close() function, you can programmatically close the dialog.
In response to the comment that this doesn't work, here's example code:-
// Must create the FileDialog on the heap, so we can call close and the dialog is deleted
// Set the Qt::WA_DeleteOnClose flag if the instance is still required
QFileDialog* fileDlg = new QFileDialog(this, QString("Select Config file"), QDir::homePath(), QString("Config (*.xml)"));
// One shot timer to close the dialog programmatically
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
connect(timer, &QTimer::timeout, [=]()
{
fileDlg->close();
timer->deleteLater();
} );
timer->start(3000);
fileDlg->exec();
In order for to display a native dialog, you have to run exec() or call one of the static functions.
Unfortunately, in Windows, this calls a blocking function in the Windows API making the displayed dialog modal, running it's own event loop. Without returning to the Qt event loop, you cannot execute the close() function using the signals/slots interface.
I tried to bypass this by calling the close() function directly from another thread, but this results in Qt trying to send an event to the underlying dialog. Since sending (as opposed to posting) events across thread boundaries is not allowed in Qt, a fatal error is generated.
So, it seems for Windows at least, this is not possible.
I have not tested on platforms other than Windows. The code I used was:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileDialog* fileDlg = new QFileDialog(0, QString("Select Config file"), QDir::homePath(), QString("Config (*.xml)"));
// spawn a new thread
QtConcurrent::run([=](){
QTimer timer;
timer.setSingleShot(true);
QEventLoop *loop = new QEventLoop;
QObject::connect(&timer, &QTimer::timeout, [=](){
fileDlg->close();
fileDlg->deleteLater();
loop->quit();
});
timer.start(3000);
loop->exec();
delete loop;
});
fileDlg->exec();
return a.exec();
}
In Windows you can use WinAPI to close the dialog:
#define WAIT(A) while (!(A)) {}
HWND dialogHandle, button;
WAIT(dialogHandle = FindWindow(NULL, L"Open")); //write here title of the dialog
WAIT(button = FindWindowEx(dialogHandle, NULL, L"Button", L"&Open")); //write here title of the button to click
SendMessage(button, BM_CLICK, 0, 0);
I am implementing a simple function where slider value is constantly displayed on label and qDebug(). I already got the label updated using signal/slots, but somehow the qDebug() thread is not working properly. I expected to see the console flooded with the value of the slider.
Below is my code:
SliderThread.h:
class HorizontalSliderThread : public QThread {
Q_OBJECT
public:
HorizontalSliderThread(Ui::MainWindow *ui);//in order to call slider value in HorizontalSliderThread class
~HorizontalSliderThread();
public slots:
void process();
private:
};
SliderThread.cpp
HorizontalSliderThread::HorizontalSliderThread(Ui::MainWindow *ui){
ui_global = *ui;
}
void HorizontalSliderThread::process(){
qDebug("Test Thread");
int value = ui_global.horizontalSlider_windowSize->value();
QObject::connect(ui_global.horizontalSlider_windowSize,SIGNAL(valueChanged(int)),ui_global.label_SliderWindowSize,SLOT(setNum(int)));//update value to label
qDebug()<<value; //update value in console
}
mainwindow.h
move Ui::MainWindow *ui; from private to public.
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThread* thread = new QThread;
HorizontalSliderThread* slider = new HorizontalSliderThread(ui);
slider->moveToThread(thread);
connect(thread, SIGNAL(started()), slider, SLOT(process()));
thread->start();
}
Current Output: qDebug() displays the value of slider once, label is updated constantly.
Expected Output: qDebug() displays the value of slider continuously, label is updated constantly.
Since label is updated when the slider is moved, then the signal/slot for this function is working, which means my thread should be working. Don't know what I'm doing wrong.
QThread implementation is reference from: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
I am fairly new to this, especially QThread, so if there is a better way to implement this function, please let me know!
Thanks a lot.
EDIT1: add slider->moveToThread(thread);
Well you've only connected the started() signal to your process() function, so your thread starts and it calls process, which dutifully shows your debug output and returns.
I suspect you want to call your process function every time the value changes, which would require another signal/slot connection (along these lines):
connect(ui_global.horizontalSlider_windowSize, SIGNAL(valueChanged(int)), thread, SLOT(setNum(int)));
Also, it looks like you intend for your HorizontalSliderThread to actually run in that separate thread you've created, in which case you'll need a call to QObject::moveToThread() in there, something along these lines:
slider->moveTothread(thread);
I have a Qt application on Linux.
I'd like to program custom keyboard shortcuts such as CTRL-Q which will then call a subroutine which quits the program.
How can I do this?
Try this:
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this, SLOT(close()));
You can create it in the contructor of your form. This allows to avoid polluting your class with a pointer to access the shortcut. You may still want to add a pointer to the shortcut if you want to access it later on. The shortcut will be deleted when the application exits, since it is parented to it. It automatically does the connection, you don't have to do it manually.
Also note that there is no default Ctrl+Q sequence on Windows, but there is one on Linux and MacOS.
Since CTRL-Q may have a menu item or toolbar entry, too, I think you're looking for QAction.
See this:
http://doc.qt.digia.com/4.6/qaction.html#shortcut-prop
LE:
Example of QAction at work:
QAction *foo = new QAction(this);
foo->setShortcut(Qt::Key_Q | Qt::CTRL);
connect(foo, SIGNAL(triggered()), this, SLOT(close()));
this->addAction(foo);
Just create a new Qt GUI project (I used QtCreator) and add that code to the main window's constructor and it should work as expected.
Please note that there is no need of freeing the memory since the Qt framework will take care of that when the app closes.
For the modern Qt (5.9 as of now):
void MainWindow::bootStrap()
{
// create shortcut
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this);
// connect its 'activated' signal to your function 'foo'
QObject::connect(shortcut, &QShortcut::activated,
this, &MainWindow::foo);
}
// somewhere in the code, define the function 'foo'
void MainWindow::foo()
{
qDebug() << "Ctrl+Q pressed.";
}
Don't forget to #include <QShortcut>.
Further info: http://doc.qt.io/qt-5/qshortcut.html
this is a sample to create file menu and exit action and connection between signal and slot.
QMenu *fileMenu = new QMenu(trUtf8("&File"));
QAction *actionExit = new QAction(tr("E&xit"));
//set "ctrl+q shortcut for exit action
actionExit->setShortcut(tr("CTRL+Q"));
//connect triggered signal of actionExit to close slot
connect(actionExit, SIGNAL(triggered()), this, SLOT(close()));
//add actionExit into file menu
fileMenu->addAction(actionExit);
I have some constructor for the class LCDRange:
LCDRange::LCDRange(QWidget *parent)
: QWidget(parent)
{
QLCDNumber *lcd = new QLCDNumber(2);
lcd->setSegmentStyle(QLCDNumber::Filled);
slider = new QSlider(Qt::Horizontal);
slider->setRange(0, 99);
slider->setValue(0);
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(lcd);
layout->addWidget(slider);
setLayout(layout);
}
but I can't understand the difference between these lines:
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
thanks in advance
Remember that we are in OO land, so we are operating on objects.
In order to connect a signal to something, those signal/slots have to be apart of an object.
Another way to think about it is you can't have a signal by itself, because a signal has to come from somewhere. Likewise, you can't have a slot all by itself it has to be attached to something.
Now, Qt allows you to connect a signal to a slot, but it also allows you to connect a signal to a signal, which is what is happening in the second connect line. This allows you to chain signals from one object to another, or you could think about it as passing a signal through.
Usually this happens when an Object or Widget has a private internal child that emits a signal, and the parent Object/Widget wants to emit the same signal to whoever is listening to it.
In the case of your example the LCDRange Widget contains a slider, which is an internal implementation detail. The user of LCDRange doesn't need to know about all the different components that make up the LCDRange (slider, lcdnumber, layout, etc), that's a basic requirement of encapsulation which is a huge advantage of OO.
However, the user of LCDRange will want to know when the value of LCDRange changes. And rather then creating a slot in LCDRange, that simply re-emits the signal valueChanged signal, you can forward or passthrough the valueChanged signal from the slider.
The following achieves the same effect of passing the signal through, however it requires much more code.
class LCDRange : public QWidget
{
// constructor and other methods
//...
signals:
void valueChanged(int)
private slots:
void sliderValueChanged(int);
// ...
};
// in the LCDRange constructor
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(sliderValueChanged(int)));
// elsewhere in LCDRange's definition
void LCDRange::sliderValueChanged( int value )
{
emit valueChanged( value );
}
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
tells, if the value of the slider gets changed then valueChanged signal will be emited and it will be reflected in LCD view. i.e display slots gets called, whose implementation will be present in QLCDNumber
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
Qt offers, mechanism of connecting one signal to another signal, it implies if slider valueChangedsignal is emited means present class valueChangedsignal is emited.
the connected slot for valueChanged gets called