Russian Qt Forum

Qt => Вопросы новичков => Тема начата: Bork от Апрель 09, 2013, 11:44



Название: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 11:44
Здравствуйте.
Стоит задача перехватить нажатие клавиши в строке ввода QInputDialog.
Для этого создан класс MyInputDigit на базе QInputDialog
Где переопределена функция keyPressEvent.
К сожалению, конструкция не работает.
Я подозреваю, что переопределение функции keyPressEven в данном случае неверный путь, но как сделать правильно я не знаю.
Помогите, пожалуйста.

Код:
class MyInputDigit :public QInputDialog
{
public:
    MyInputDigit(QWidget *parent = 0):QInputDialog(parent)
    {
    }
    void keyPressEvent(QKeyEvent *event)
    {
        ShowMessage("text");
    }
};
ShowMessage("text") - Выводит сообщение с помощью QMessageBox и работает нормально.

Вызов диалога:

Код:
    bool bOk;
    MyInputDigit::getText( 0, "Ввод:", "ВВЕДИТЕ НОМЕР", QLineEdit::Normal, "", &bOk);
   


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 09, 2013, 11:48
сигнал textValueChanged ( const QString & text ) не подойдет?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 11:54
сигнал textValueChanged ( const QString & text ) не подойдет?

Я правильно понимаю, что класс будет выглядеть таким образом?
Код:
class MyInputDigit :public QInputDialog
{
public:
    MyInputDigit(QWidget *parent = 0):QInputDialog(parent)
    {
    }
    void textValueChanged(const QString &text)
    {
        ShowMessage(text);
    }
};

Если да, то не работает:(


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 09, 2013, 11:57
Нет, понимаешь неправильно. Читай про сигналы/слоты


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: GreatSnake от Апрель 09, 2013, 12:28
2 Bork:
Коли используешь статическую функцию QInputDialog::getText() наследоваться от QInputDialog можешь до посинения)


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 12:32
Нет, понимаешь неправильно. Читай про сигналы/слоты

Хорошо, усложняю:
MyInputDigit.h
Код:
class MyInputDigit :public QInputDialog
{
public:
    MyInputDigit(QWidget *parent = 0);
    void textValChanged();

};

MyInputDigit.cpp
Код:
MyInputDigit::MyInputDigit(QWidget *parent):QInputDialog(parent)
{
    connect(this, SIGNAL(textValueChanged(const QString &text)), this, SLOT(textValChanged()));
}

void MyInputDigit::textValChanged()
{
    ShowMessage("text");
}

В такой реализации тоже не работает.
Тут мне непонятно, к чему привязывать сигнал. Когда есть кнопка то все понятно, привязываешь к кнопке и пишешь реализацию, а тут?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 12:34
2 Bork:
Коли используешь статическую функцию QInputDialog::getText() наследоваться от QInputDialog можешь до посинения)


Почему?
Я же использую getText() от наследника.


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: GreatSnake от Апрель 09, 2013, 12:36
Почему?
Я же использую getText() от наследника.
А толку-то, коли она статическая?
Запускай свой MyInputDigit через exec() и получишь результат)


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 12:57
А толку-то, коли она статическая?
Запускай свой MyInputDigit через exec() и получишь результат)

Возвращаемся к коду из первого поста
теперь вызов такой:
Код:
    MyInputDigit *Inp = new MyInputDigit;
    Inp->exec();

тоже не работает:(


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 09, 2013, 13:07
Код:
class MyInputDigit :public QInputDialog
{
public:
    MyInputDigit(QWidget *parent = 0);
    void textValChanged();

};

Код:
MyInputDigit::MyInputDigit(QWidget *parent):QInputDialog(parent)
{
    connect(this, SIGNAL(textValueChanged(const QString &text)), this, SLOT(textValChanged()));
}

void MyInputDigit::textValChanged()
{
    ShowMessage("text");
}

В такой реализации тоже не работает.

Конечно не работает, textValChanged() это не слот, а просто метод


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 14:17
Конечно не работает, textValChanged() это не слот, а просто метод

Исправил, теперь так:
Код:
class MyInputDigit :public QInputDialog
{
public:
    MyInputDigit(QWidget *parent = 0);

public slots:
    void textValChanged();
};

Код:
MyInputDigit::MyInputDigit(QWidget *parent):QInputDialog(parent)
{
    connect(this, SIGNAL(textValueChanged(const QString &text)), this, SLOT(textValChanged()));
}

void MyInputDigit::textValChanged()
{
    ShowMessage("text");
}

Не помогло.


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: GreatSnake от Апрель 09, 2013, 14:22
Мде...
Где в теле MyInputDigit Q_OBJECT макрос?

Может всё-таки взять и прочитать наконец-то про Сигналы и слоты (http://www.doc.crossplatform.ru/qt/4.7.x/signalsandslots.html), а не плакаться, что ничего не работает?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Alex Custov от Апрель 09, 2013, 14:36
Не помогло.

Прочитай доку по сигналам как написано выше и пойми её. Без этого никуда.


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 09, 2013, 16:57
Мде...
Где в теле MyInputDigit Q_OBJECT макрос?

Может всё-таки взять и прочитать наконец-то про Сигналы и слоты (http://www.doc.crossplatform.ru/qt/4.7.x/signalsandslots.html), а не плакаться, что ничего не работает?

Спасибо, документацию прочитал, макрос поставил.

В моем случае, насколько я понял, сигнал textValueChanged испускает объект MyInputDigit, он же и принимает.
Получается, что написанный в конструкторе класса 
    connect(this, SIGNAL(textValueChanged(const QString &text)), this, SLOT(textValChanged()));
написан правильно, или я опять ошибаюсь?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: GreatSnake от Апрель 09, 2013, 17:01
написан правильно, или я опять ошибаюсь?
да, правильно


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 10, 2013, 10:47
да, правильно

Тогда
Код:
class MyInputDigit :public QInputDialog
{
    Q_OBJECT

public:
    explicit MyInputDigit(QWidget *parent = 0);

public slots:
    void textValChanged();

};

Код:
MyInputDigit::MyInputDigit(QWidget *parent)
    :QInputDialog(parent)
{
    connect(this, SIGNAL(textValueChanged(const QString &text)), this, SLOT(textValChanged()));
}

void MyInputDigit::textValChanged()
{
    QMessageBox msg;
    msg.setText("text");
    msg.exec();
}

Объект генерит сигнал автоматически при нажатии кнопки, слот принимающий этот сигнал я описал
должно работать, правильно?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 10, 2013, 10:52
Объект генерит сигнал автоматически при нажатии кнопки, слот принимающий этот сигнал я описал
должно работать, правильно?

Неправильно, объект генерирует сигнал не при нажатии кнопки, а при изменении текста


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 10, 2013, 11:10
Неправильно, объект генерирует сигнал не при нажатии кнопки, а при изменении текста

Да, прошу прощения, именно это я имел ввиду.
Изменяемый текст, на сколько я понимаю, находится в окне ввода.
Т.е. любое нажатие буквы или цифры приводит к его изменению.

Значит класс должен работать, так?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 11, 2013, 13:42
Вот класс с работающим textValueChanged():

MyInputDigit.h
Код:
class MyInputDigit :public QInputDialog
{
    Q_OBJECT

public:
    MyInputDigit(QWidget *parent = 0);
public slots:
    void textValChanged(QString text);

};

MyInputDigit.cpp
Код:
MyInputDigit::MyInputDigit(QWidget *parent)
    :QInputDialog(parent)
{
    connect(this, SIGNAL(textValueChanged(QString)), this, SLOT(textValChanged(QString)));
}

void MyInputDigit::textValChanged(QString text)
{
    QMessageBox msg;
    msg.setText(text);
    msg.exec();
}

С помощью этого класса можно решить изначально поставленную задачу, но сложно.
Для реализации потребуется каждый раз проверять весь массив на валидность, что долго, дорого и не очень красиво.
По этому считаю более правильным ловить именно последний введенный символ.
Придется возвращаться к keyPressEvent().
Тут, видимо, засада в фокусе, вернее в том месте где я его ловлю.
Как я понимаю, keyPressEvent() ловит событие где-то внизу, на форме, а само событие происходит вверху в QLineEdit, по этому keyPressEvent() и не срабатывает.
Может у кого был опыт решения подобной проблемы?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 11, 2013, 13:44
Какой массив надо проверять на какую валидность? Бери последний символ из строки и смотри на него. Или построй свой собственный диалог и лови что хочешь внутри


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 11, 2013, 13:45
Какой массив надо проверять на какую валидность? Бери последний символ из строки и смотри на него. Или построй свой собственный диалог и лови что хочешь внутри

а что делать если пользователь ввел символ в середину?
Собственный диалог пока не рассматриваю.


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 11, 2013, 13:48
Какой массив надо проверять на какую валидность? Бери последний символ из строки и смотри на него. Или построй свой собственный диалог и лови что хочешь внутри

а что делать если пользователь ввел символ в середину?
Собственный диалог пока не рассматриваю.

Я не знаю что делать, я же не знаю задачи


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 11, 2013, 14:04
Я не знаю что делать, я же не знаю задачи

Виноват, задача следующая:
Предположим на выходе нужно получить дробное число с двумя знаками после запятой
Поймать последний введенный символ
Понять что это (цифра, буква, дробный разделитель)
Либо разрешить ввод этого символа либо убрать его из строки (проигнорировать его ввод).


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 11, 2013, 14:32
пили свой диалог с валидаторами либо перехватом клавишь, раз задача такая разносторонняя


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 11, 2013, 15:13
пили свой диалог с валидаторами либо перехватом клавишь, раз задача такая разносторонняя

Вы считаете, другого пути, кроме создания своего диалога, в данном случае нет?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: mutineer от Апрель 11, 2013, 15:27
ИМХО тебе нужно добраться до внутренного QTextEdit чтобы все это реализовать, но корректных способов это сделать я не вижу. Самый лучший способ - сделать свой диалог


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: GreatSnake от Апрель 11, 2013, 20:05
А может не изобретать велосипед и просто включить QInputDialog::DoubleInput?


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 12, 2013, 09:28
А может не изобретать велосипед и просто включить QInputDialog::DoubleInput?

Мало цифр.
Задачу с дробным числом тип double решает, хотя хотелось бы иметь больше чем 10 миллиардов, хотя бы на порядок.
Но параллельно, с помощью этого класса хочется еще получать и EAN13, а вот он в int уже не пролезет, a long int туда воткнуть у меня не получилось.:(


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: GreatSnake от Апрель 12, 2013, 09:45
Тогда нужно на QLineEdit навесить validator. Либо QRegExpValidator, либо производный от QValidator.
Достучаться до QLineEdit в QInputDialog можно через QInputDialog::findChild< QLineEdit* >(), что есть hack.
Имхо проще и лучше написать свой диалог.


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 12, 2013, 09:53
Ребята, большое вам спасибо за помощь, буду думать...


Название: Re: Как перехватить нажатие клавиши в QInputDialog?
Отправлено: Bork от Апрель 19, 2013, 08:46
Вот такой у меня получился класс.

MyInputBox.h
Код:
#include <QtGui>

#define ONLY_DIGITS 1
#define MONEY 2
#define ALL_KEYS 3

class MyInputBox :public QDialog
{
    Q_OBJECT

public:
    MyInputBox(QDialog *parent = 0);
    void setLabelText(QString label);
    void setMaxLength(int maxLength);
    void setInputMask(int inputMask);
    void setText(QString text);
    QString text();
    bool getResult();
    static QString getText(const QString title, const QString label, const QString text="", int mask=1, bool *ok=0, int maxLength=255);
    ~MyInputBox();

private:
    int _InputMask;
    bool _buttonResult;
    QFont *mainFont;
    QVBoxLayout *layoutVmain;
    QHBoxLayout *layoutHbutton;
    QLabel *labelString;
    QLineEdit *lineeditInput;
    QPushButton *buttonOk;
    QPushButton *buttonCancel;
    bool eventFilter(QObject *target, QEvent *event);


public slots:
    void buttonOkSlot();
    void buttonCancelSlot();

};

MyInputBox.cpp
Код:
MyInputBox::MyInputBox(QDialog *parent)
    :QDialog(parent)
{
    setMinimumWidth(160);
    setMinimumHeight(100);
    mainFont = new QFont;
    mainFont->setPixelSize(16);

    labelString = new QLabel("Input text:");
    lineeditInput = new QLineEdit;
    buttonOk = new QPushButton("Ok");
    buttonCancel = new QPushButton("Cancel");

    layoutHbutton = new QHBoxLayout;
    layoutHbutton->addWidget(buttonOk);
    layoutHbutton->addWidget(buttonCancel);

    layoutVmain = new QVBoxLayout(this);
    layoutVmain->addWidget(labelString);
    layoutVmain->addWidget(lineeditInput);
    layoutVmain->addLayout(layoutHbutton);
    layoutVmain->addStretch();

    setFont(*mainFont);
    setWindowTitle("MyInputBox");
    _InputMask=ONLY_DIGITS;
    _buttonResult=false;


    connect(buttonOk, SIGNAL(clicked()), this, SLOT(buttonOkSlot()));
    connect(buttonCancel, SIGNAL(clicked()), this, SLOT(buttonCancelSlot()));
    lineeditInput->installEventFilter(this);

}

void MyInputBox::setLabelText(QString label)
{
    labelString->setText(label);
}

void MyInputBox::setMaxLength(int maxLength)
{
    lineeditInput->setMaxLength(maxLength);
}

void MyInputBox::buttonOkSlot()
{
    _buttonResult=true;
    close();
}

void MyInputBox::buttonCancelSlot()
{
    lineeditInput->setText("");
    close();
}

void MyInputBox::setInputMask(int inputMask)
{
    if ((inputMask>0)&&(inputMask<4))_InputMask=inputMask;
}

QString MyInputBox::text()
{
    return lineeditInput->text();
}

void MyInputBox::setText(QString text)
{
    lineeditInput->setText(text);
}

bool MyInputBox::getResult()
{
    return _buttonResult;
}

QString MyInputBox::getText(const QString title, const QString label, const QString text, int mask, bool *ok, int maxLength)
{
    QString TextReturn;
    MyInputBox Input;
    Input.setWindowTitle(title);
    Input.setLabelText(label);
    Input.setText(text);
    Input.setInputMask(mask);
    Input.setMaxLength(maxLength);
    Input.exec();

    *ok=Input.getResult();
    TextReturn=Input.text();
    return TextReturn;
}

bool MyInputBox::eventFilter(QObject *target, QEvent *event)
{
    if (target == lineeditInput)
    {
        if (event->type() == QEvent::KeyPress)
        {
            if (_InputMask==ALL_KEYS)
            {
                lineeditInput->event(event);
                return true;
            }
            else if (_InputMask==ONLY_DIGITS)
            {
                QKeyEvent *keyEvent = (QKeyEvent *)event;
                if ((keyEvent->key() == Qt::Key_0)||
                        (keyEvent->key() == Qt::Key_1)||
                        (keyEvent->key() == Qt::Key_2)||
                        (keyEvent->key() == Qt::Key_3)||
                        (keyEvent->key() == Qt::Key_4)||
                        (keyEvent->key() == Qt::Key_5)||
                        (keyEvent->key() == Qt::Key_6)||
                        (keyEvent->key() == Qt::Key_7)||
                        (keyEvent->key() == Qt::Key_8)||
                        (keyEvent->key() == Qt::Key_9)||
                        (keyEvent->key() == Qt::Key_Tab)||
                        (keyEvent->key() == Qt::Key_Backspace)||
                        (keyEvent->key() == Qt::Key_Delete)||
                        (keyEvent->key() == Qt::Key_Right)||
                        (keyEvent->key() == Qt::Key_Left))
                    lineeditInput->event(event);
                return true;
            }
            else if (_InputMask==MONEY)
            {
                QKeyEvent *keyEvent = (QKeyEvent *)event;
                if ((keyEvent->key() == Qt::Key_Tab)||
                        (keyEvent->key() == Qt::Key_Backspace)||
                        (keyEvent->key() == Qt::Key_Delete)||
                        (keyEvent->key() == Qt::Key_Right)||
                        (keyEvent->key() == Qt::Key_Left))
                    lineeditInput->event(event);
                else if ((keyEvent->key() == Qt::Key_Comma)||(keyEvent->key() == Qt::Key_Period))
                {
                    if (lineeditInput->text().indexOf(',')<0) lineeditInput->insert(",");
                }
                else if ((keyEvent->key() == Qt::Key_0)||
                        (keyEvent->key() == Qt::Key_1)||
                        (keyEvent->key() == Qt::Key_2)||
                        (keyEvent->key() == Qt::Key_3)||
                        (keyEvent->key() == Qt::Key_4)||
                        (keyEvent->key() == Qt::Key_5)||
                        (keyEvent->key() == Qt::Key_6)||
                        (keyEvent->key() == Qt::Key_7)||
                        (keyEvent->key() == Qt::Key_8)||
                        (keyEvent->key() == Qt::Key_9))
                {
                    if (lineeditInput->text().indexOf(',')<0) lineeditInput->event(event);
                    else
                    {
                        if (lineeditInput->text().length()-(lineeditInput->text().indexOf(',')+1)<2) lineeditInput->event(event);
                        else
                        {
                            if (lineeditInput->text().indexOf(',')>=lineeditInput->cursorPosition()) lineeditInput->event(event);
                        }
                    }
                }
                return true;
            }
        }
    }
    return QDialog::eventFilter(target, event);
}

MyInputBox::~MyInputBox()
{
    delete mainFont;
    delete labelString;
    delete lineeditInput;
    delete buttonOk;
    delete buttonCancel;

    delete layoutHbutton;
    delete layoutVmain;
}


Вызов:
Код:
bool bOk;
MyInputBox::getText("Ввод:", "ВВЕДИТЕ СУММУ ОТЧЕТА", "", 2, &bOk);

Прошу высказывать предложения по оптимизации.