QT c++: drop in multi line edite - c++

Im beginner in qt and i do my first project. I am encountering a problem.
I put somes edit line in a scroll area. All of this edit text should countains path to files. To make this app more userfriendly i decided to implement a drag and drop. By this way, users can just take a file from their explorer and drop it to line edit which will be fill with the path of the file.
My problem is: When i try to drop, all edit line where my mouse passed on, will be fill with the path of the file. If i change if statements by else if, its the first edit line that my mouse passed on which will be fill but not the one where my mouse is at the moment of the drop.
here the code:
void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
e->accept()
}
void MainWindow::dropEvent(QDropEvent *e)
{
foreach (const QUrl &url, e->mimeData()->urls()) {
QString fileName = StringManagement::getDir(url.toLocalFile());
if(ui->lineEdit->underMouse())
ui->lineEdit->setText(fileName);
if(ui->lineEdit_2->underMouse())
ui->lineEdit_2->setText(fileName);
if(ui->lineEdit_5->underMouse())
ui->lineEdit_5->setText(fileName);
if(ui->lineEdit_9->underMouse())
ui->lineEdit_9->setText(fileName);
if(ui->lineEdit_10->underMouse())
ui->lineEdit_10->setText(fileName);
if(ui->lineEdit_11->underMouse())
ui->lineEdit_11->setText(fileName);
}
}
On other point that i dont really understand is:
<pre><code>void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
qInfo() << "enter";
e->accept();
}
void MainWindow::dragLeaveEvent(QDragLeaveEvent *e){
qInfo() << "leave";
e->accept();
}
when i put my mouse on an edit line and i stay on it, i will see both message in the console... i expected to see the first one when my mouse enter in and the second one when my mouse leave it.
thank you in advance for your helps.

Following your answer to my comment I'll try to help you.
I'm not an expert at Qt so I may be wrong but since there is no answer yet I'll try to give one.
I tried to reproduce your code and for the second question:
void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
qInfo() << "enter";
e->accept();
}
void MainWindow::dragLeaveEvent(QDragLeaveEvent *e)
{
qInfo() << "leave";
e->accept();
}
I have the same behaviour if MainWindow and the lineEdits both manage drag and drop (setAcceptDrops(true)). I think that you "enter" when you enter the MainWindow and then "leave" when you enter the lineEdit since it manages itself the drag and drop.
If you set :
ui->lineEdit->setAcceptDrops(false);
Then you don't "leave" anymore.
For the first part
If I try to reproduce your code, I have a problem with the underMouse() function.
Maybe your problem comes from here?
If I implement my own underMouse() then everything is fine.
I hope someone else with better Qt knowledge will come to your help.

Ok i find a solution. I dont really like it because i dont find it really clean but that works. If others have cleaner solution im open to it. I put my solution here. Maybe that could help someone in the future. I finaly didn't use drop methode but i used an eventFilter which give me the posibility to have a better management of events.
<pre><code>MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
this->data = DataModel::GetInstance();
ui->setupUi(this);
setAcceptDrops(true);
//ui->lineEdit->dragEnabled();
//ui->lineEdit->setAcceptDrops();
installEventFilter(this);
ui->lineEdit->installEventFilter(this);
ui->lineEdit_2->installEventFilter(this);
ui->lineEdit_5->installEventFilter(this);
ui->lineEdit_9->installEventFilter(this);
ui->lineEdit_10->installEventFilter(this);
ui->lineEdit_11->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::dragEnterEvent(QDragEnterEvent *e)
{
qInfo() << "enter";
e->accept();
}
bool MainWindow::eventFilter(QObject* obj, QEvent* event){
if(event->type() == QEvent::DragEnter){
if(obj == ui->lineEdit){
this->flag = 1;
}
else if(obj == ui->lineEdit_2){
this->flag = 2;
}
else if(obj == ui->lineEdit_5){
this->flag = 3;
}
else if(obj == ui->lineEdit_9){
this->flag = 4;
}
else if(obj == ui->lineEdit_10){
this->flag = 5;
}
else if(obj == ui->lineEdit_11){
this->flag = 6;
}
qInfo()<<"flag" <<this->flag;
}
if(event->type() == QEvent::Drop){
qInfo()<< obj;
QDropEvent *drop = static_cast<QDropEvent *>(event);
foreach (const QUrl &url, drop->mimeData()->urls()) {
QString fileName = StringManagement::getDir(url.toLocalFile());
qInfo()<<"flag drop" <<this->flag;
if(this->flag == 1){
ui->lineEdit->setText(fileName);
}
else if(this->flag == 2){
ui->lineEdit_2->setText(fileName);
}
else if(this->flag == 3){
ui->lineEdit_5->setText(fileName);
}
else if(this->flag == 4){
ui->lineEdit_9->setText(fileName);
}
else if(this->flag == 5){
ui->lineEdit_10->setText(fileName);
}
else if(this->flag == 6){
ui->lineEdit_11->setText(fileName);
}
return true;
}
}
}
</code></pre>
I dont manage return in the filter for now but the idea is here.

Related

Different behavior of events in different projects

In the last question, I had a problem with placing the cursor in the right place when clicking on the LineEdit with the mouse.
The problem was solved, I, with God's help, wrote an algorithm that solves my problem. I wrote it in an EMPTY project, where there is nothing but LineEdit. Everything worked great there. Here is the code:
if(object == ui->lineEdit_newClientPhone && event->type() == QEvent::MouseButtonRelease)
{
QString line = ui->lineEdit_newClientPhone->displayText();
qDebug() << line;
ui->lineEdit_newClientPhone->setFocus();
bool isValid = true;
for(int i = 0; i<=15; i++){
if(line[i] == '_'){
ui->lineEdit_newClientPhone->setCursorPosition(i);
isValid = false;
break;
}
}
if(isValid){
ui->lineEdit_newClientPhone->setCursorPosition(16);
}
}
It worked great. You click on any place in lineEdit, the mouse cursor is placed on the first empty "_" character. I joyfully ran to transfer it to the main project.
But then I encountered a strange behavior - in the main project, exactly copied code does not give such behavior. When you click on lineEdit with the mouse, the cursor is placed in the place where you clicked. I debugged all the events associated with this LineEdit and found strange behavior - the order of the events is different. Excluding unnecessary events, which were the MOST:
if(object == ui->lineEdit_newClientPhone){
if(event->type() != QEvent::Paint && event->type() != QEvent::MouseMove && event->type() != QEvent::HoverMove){
qDebug() << event->type();
}
}
Got this result in "EMPTY" project:
QEvent::MouseButtonPress
QEvent::MouseButtonRelease
QEvent::InputMethodQuery
But in the main project, the sequence turned out to be different:
QEvent::MouseButtonPress
QEvent::InputMethodQuery
QEvent::MouseButtonRelease
I don't know if this is the case, but in this way, my logic does not work and the cursor remains in the place where you clicked. I was able to fix the situation by changing the event to QEvent::MouseButtonRelease, but this way I get mocking cursor travels first to the place where you clicked, then to the place I need. What could be the problem and how can it be fixed? Thanks to all!
I don't think this is the right decision, so I would like to hear more solutions, but QTimer::singleShot helped me
f(object == ui->lineEdit_newClientPhone && event->type() == QEvent::MouseButtonPress){
QTimer::singleShot(0,ui->lineEdit_newClientPhone,[this]
{
QString line = ui->lineEdit_newClientPhone->displayText();
qDebug() << line;
ui->lineEdit_newClientPhone->setFocus();
bool isValid = true;
for(int i = 0; i<=15; i++){
if(line[i] == '_'){
ui->lineEdit_newClientPhone->setCursorPosition(i);
isValid = false;
break;
}
}
if(isValid){
ui->lineEdit_newClientPhone->setCursorPosition(16);
}
});
}

How to enable a dynamic whatsthis-string in Qt using QWhatsThis?

In order to have a dynamic what's this string for a widget in Qt the following almost works (following the documentation http://doc.qt.io/qt-5/qtwidgets-widgets-tooltips-example.html ):
class MyEdit : public QLineEdit {
Q_OBJECT
public:
bool event(QEvent*e) {
if (e && e->type() == QEvent::WhatsThis) {
if (QHelpEvent *helpEvent = reinterpret_cast<QHelpEvent *>(e)) {
QWhatsThis::showText(helpEvent->globalPos(), "My text...");
return true;
}
}
return QLineEdit::event(e);
}
};
Activating what's this for the window and clicking on the widget shows "My text" (the actual text is more complicated).
Issues:
Activating what's this for the window and hovering over this widget shows a dead cursor
Shift-F1 does not work inside the widget.
The first issue could be worked around by calling setWhatsThis("Dummy text"); with a non-empty string, but it feels like a hack and Shift-F1 in this widget shows "Dummy text".
Is there a non-hack way of handling it - especially so that it will not be broken by updates?
In case someone else stumbles on this issue the following seems to handle the Shift-F1:
class MyEdit : public QLineEdit {
Q_OBJECT
public:
bool event(QEvent*e) {
if (e && e->type() == QEvent::WhatsThis) {
if (QHelpEvent *helpEvent = reinterpret_cast<QHelpEvent *>(e)) {
QWhatsThis::showText(helpEvent->globalPos(), "My text...");
return true;
}
}
if (e && e->type() == QEvent::KeyPress) {
if (QKeyEvent *qk = reinterpret_cast<QKeyEvent *>(e)) {
if (qk->key() == Qt::Key_F1 && (qk->modifiers()&Qt::ShiftModifier)) {
QWhatsThis::showText(w.mapToGlobal(w.inputMethodQuery(Qt::ImCursorRectangle).toRect().center()), "My text...");
qk->accept();
return true;
}
}
}
return QLineEdit::event(e);
}
};
and combined with calling setWhatsThis("Dummy text"); also the hovering-part. However, it is not an elegant solution.

QLineEdit the function selectAll() didn't work?

I user QLineEdit like this, and anybody know anything is wrong:
if (event->modifiers() == Qt::ControlModifier
&& event->key()== Qt::Key_A) {
qDebug() << "Ctrl+A pressed";
m_lineEdit->setFocus(Qt::ShortcutFocusReason);
m_lineEdit->selectAll();
}
Try to use timer to make sure all events are processed and then selection is done:
QTimer::singleShot(0, m_lineEdit, SLOT(selectAll()));
instead of m_lineEdit->selectAll();

Qt How to highlight menu? [duplicate]

This question already has answers here:
How to focus menuBar() with Qt
(2 answers)
Closed 4 years ago.
I need to do hide/show main menu function by pressing the Alt key (like in FireFox). I know how to hide and show it, but I can't highlight menu after showing it. I've tried menuBar()->actions()[0].hover(), activateWindow(), setActiveAction(), activate(QAction::Hover), but nothing helps. How can I do it? Maybe I should use WinApi functions instead of Qt?
bool MainWindow::event(QEvent *event){
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *ke = static_cast<QKeyEvent*>(event);
if (ke->key() == Qt::Key_Alt)
{
keyReleaseEvent(ke);
return true;
}
}
return QMainWindow::event(event);
}
Handle Alt
void MainWindow::keyReleaseEvent (QKeyEvent* event)
{
if (event->key() == Qt::Key_Alt){
if (menuBar()->isHidden()){
menuBar()->show();
menuBar()->setFocus(Qt::MenuBarFocusEvent); //here I trying to highlight the menu
}
else{
menuBar()->hide();
{
}
}
Duplicate of How to focus menuBar() with Qt (which I just answered)
Because the answer isn't accepted on the other question, I can't flag this one as a duplicate. Including answer below as well:
I wanted to do the same thing. My solution, complete example, as a gist:
https://gist.github.com/xim/ee56564f425151ea2fa70f730d644873
As it contains a lot of other junk, a minimal example:
class AutoHidingMenuBar : public QMenuBar {
Q_OBJECT
public:
AutoHidingMenuBar() : QMenuBar() {
setMaximumHeight(0);
connect(qApp, &QApplication::focusChanged, this, &AutoHidingMenuBar::focusChanged);
}
private slots:
void focusChanged(QWidget *from, QWidget *to) {
bool inFocus = hasFocus() || isAncestorOf(focus) || hasFocusedChild();
if (inFocus && maximumHeight() == 0) {
auto action = activeAction();
setMaximumHeight(100);
if (action) {
// XXX This is a bit of a hack. We could do
// QCoreApplication::processEvents();
// setActiveAction(action);
// with almost the same effect, but then we *open* the first menu on single alt press...
auto evt = new QMouseEvent(QEvent::MouseMove, actionGeometry(action).center(), Qt::NoButton, Qt::NoButton, Qt::NoModifier);
QCoreApplication::postEvent(this, evt);
}
} else if (!inFocus && maximumHeight() != 0)) {
setMaximumHeight(0);
}
}
private:
bool hasFocusedChild();
};
Try to debug it and see what is happening.
You can do something like:
if (menuBar()->hasFocus())
qDebug() << " I have the focus";
else
qDebug() << " I don't have the focus";
And see if it has the focus but works bad or if it has no focus which I think that is problem... somewhere it is losing it
A little trick that may help you is using:
QTimer::singleShot(0, menuBar(), SLOT(setFocus()));
on your MainWindow::keyReleaseEvent
And last thing... Note that set focus needs a focusPolicy, maybe this helps you.

Qt c++ play sound on key press - stops working after a few seconds

I'm making an apllication which needs to play .wav file when user type something inside QTextEdit. I made some code but after minute or less the sound stops, so I made silly workarround. After 30 clicks I invoke sound->stop(); and then the loop start again, that works, but it's not good, can you give better solution. Here is my code:
int count = 0;
bool MainWindow::eventFilter(QObject *o, QEvent *e){
if(e->type() == QEvent::KeyPress)
{
tipka->play();
tipka->seek(0);
count++;
if(count == 30){
tipka->pause();
count = 0;
}
}
return false;
}
You can use QSound. It doesn't provide any seeking capabilities but it gives you the ability to loop, play, and stop. It's not feature rich but it gets the job done.
QSound sound("File name.wav");
sound.play();
sound.stop();
Also, you can use its static function to play a sound.
QSound::play("File name.wav");
Try this, and thank me later :)
in your MainWindow constructor -
installEventFilter(this);
in header-
protected:
bool eventFilter(QObject *, QEvent*);
in cpp-
bool MainWindow::eventFilter(QObject *o, QEvent *e){
Q_UNUSED(o);
if(e->type() == QEvent::KeyRelease)
{ player->stop();
player->setMedia(QUrl("qrc:/sounds/button_push.mp3"));
player->play();
}
return false;
}