Russian Qt Forum
Ноябрь 24, 2024, 08:39 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Обработка событий клавиатуры (Проблема решена)  (Прочитано 15593 раз)
begin
Гость
« : Август 04, 2010, 13:59 »

Только начинаю изучать Qt.
Создаю окно, в котором расположены 20 одинаковых ячеек.
С этим проблем не возникло.
Теперь хочу сделать так, чтобы по нажатию кнопок A и B на клавиатуре менялись свойства рядов ячеек.
Кнопки нажимаю, но ничего не происходит. Почему - не понимаю. Подскажите.
prog.cpp
Код:
#include <QApplication>
#include <QMainWindow>
#include "basicmenu.h"

Basicmenu *chiOfBasicMenu;

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow *window = new QMainWindow;
window -> setWindowTitle("Main Window");
window -> setGeometry ( 0, 0, 800, 480);
chiOfBasicMenu = new Basicmenu(window);
chiOfBasicMenu -> setGeometry (0, 0, 800, 480);
window->show();
return app.exec();
}
basicmenu.h
Код:
#ifndef BASICMENU_H
#define BASICMENU_H

#include <QGroupBox>
#include "cell.h"

class Basicmenu : public QWidget
{
public:
Basicmenu (QWidget *parent = 0);
void Highlightofrow(int numberOfRow);
void KeyPressEvent(QKeyEvent *event);
QGroupBox *borderOfMainMenu;
Cell *cellOfArray[5][4];

};
#endif
basicmenu.cpp
Код:
#include <QKeyEvent>
#include "basicmenu.h"


Basicmenu::Basicmenu(QWidget *parent)
:QWidget(parent)
{
borderOfMainMenu = new QGroupBox(this);
borderOfMainMenu -> setGeometry ( 0, 0, 800, 480);
borderOfMainMenu -> setStyleSheet("background-color: #0821FF;");
for (int i=0; i<5; i++)
{
for (int j=0; j<4; j++)
{
cellOfArray[i][j] = new Cell(borderOfMainMenu);
cellOfArray[i][j] -> setGeometry( (40*(j+1)+150*j), (30*(i+1)+60*i), 150, 60);
}
}
}

void Basicmenu::Highlightofrow(int numberOfRow)
{
for (int i=0; i<5; i++)
cellOfArray[i][numberOfRow] -> borderOfCell -> setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
}

void Basicmenu::KeyPressEvent(QKeyEvent *event)
{
event->accept();
switch (event->key())
{
case 0x41: Highlightofrow(1);
break;
case 0x42: Highlightofrow(2);
break;
}
}
cell.h
Код:
#ifndef CELL_H
#define CELL_H

#include <QFrame>
#include <QLabel>
#include <QCheckBox>
#include <QVBoxLayout>

class Cell : public QWidget
{
public:
Cell(QWidget *parent = 0);
QFrame *borderOfCell;
QLabel *nameOfCell;
QCheckBox *visibilityOfCell;
QVBoxLayout *placingInCell;
};
#endif
cell.cpp
Код:
#include "cell.h"

Cell::Cell(QWidget *parent)
:QWidget(parent)
{
borderOfCell = new QFrame(this);
borderOfCell -> setFrameStyle(QFrame::WinPanel | QFrame::Raised);
borderOfCell -> setStyleSheet("color: #F4FF23;" "background-color: #4356FF;");
placingInCell = new QVBoxLayout;
nameOfCell = new QLabel(borderOfCell);
visibilityOfCell = new QCheckBox(borderOfCell);
placingInCell -> addWidget(nameOfCell, 0, Qt::AlignCenter);
placingInCell -> addWidget(visibilityOfCell, 0, Qt::AlignCenter);
borderOfCell ->setLayout(placingInCell);
borderOfCell-> setGeometry (0, 0, 150, 60);
}
« Последнее редактирование: Август 05, 2010, 10:38 от begin » Записан
Anarion
Гость
« Ответ #1 : Август 04, 2010, 14:54 »

Судя по всему, в фокусе ввода с клавиатуры находится внутренний виджет, объект класса Cell. Проверил это переопределив для класса Cell событие keyPressEvent(). Причем в виджет Basicmenu, который и должен (по замыслу) обрабатывать нажатие, событие нажатия не попадает вообще.
На вскидку 2 решения:
1) Заставить обрабатывать событие родительский виджет класса Basicmenu (хз, как)
2) Посылать от Cell'ов сигнал о нажатии виджету Basicmenu, предварительно соединив со слотом, в котором и обрабатывать нажатия клавиш.
Записан
begin
Гость
« Ответ #2 : Август 04, 2010, 15:13 »

Насчет второго варианта - это вариант, как говорится, в лоб. Скорее всего получится, но это будет не очень красиво.
А вот как можно в этом случае перевести фокус ввода на Basicmenu?
Записан
SASA
Гость
« Ответ #3 : Август 04, 2010, 15:52 »

Создайте экшен и повесте на него горячую клавишу.

З.Ы. Не пользуьтесь магическими константами типа 0x41. В КуТэ есть перечисления со всеми клавишами.
Записан
begin
Гость
« Ответ #4 : Август 04, 2010, 15:59 »

Создайте экшен и повесте на него горячую клавишу.

З.Ы. Не пользуьтесь магическими константами типа 0x41. В КуТэ есть перечисления со всеми клавишами.
Если можно - более развернуто. Не очень понял вашу мысль.
Насчет "магических констант" - а чем плохо их использовать?
Записан
Anarion
Гость
« Ответ #5 : Август 04, 2010, 16:39 »

На сколько понимаю, самым первым событие нажатия клавиши получает QMainWindow *window = new QMainWindow;
Поэтому, как вариант, можно унаследоваться от него и уже в нем обрабатывать все нажатия или же делать экшены (QAction). В нем же и создавать остальные объекты, например тот же chiOfBasicMenu = new Basicmenu(window);

Если делать без наследования:
1) экшн надо добавлять в объект chiOfBasicMenu, но т.к. фокус он не получает, то экшн не отработает.
2) если добавлять экшн в window, то надо будет с чем-то соединять сигналы-слоты от экшенов, что без наследования врядли удасться.
Записан
begin
Гость
« Ответ #6 : Август 04, 2010, 16:42 »

На сколько понимаю, самым первым событие нажатия клавиши получает QMainWindow *window = new QMainWindow;
Странно, а в книге по Qt нашл вот такой абзац:
"Большинство типов событий, включая события от мыши и клавиатуры, могут передаваться дальше. Если событие не было обработано по пути к объекту наначения, или самим объектом, то процесс обработки события повторяется, но на этот раз объектом назначения становится виджет-владелец. Так продолжается до тех пор, пока событие не будет обработано, либо пока событие не достигнет виджет самого верхнего уровня."
Может быть все-таки наоборот, сначала событие получает самый младший?
Записан
Anarion
Гость
« Ответ #7 : Август 04, 2010, 19:55 »

Да, Вы правы (признаю свою ошибку). Можно сделать таким образом:
main.cpp
Код:
#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);

  MainWindow *window = new MainWindow;
  window->show();

  return app.exec();
}

mainwindow.h
Код:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include "basicmenu.h"

class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  MainWindow(QWidget *parent = 0);
  Basicmenu *chiOfBasicMenu;

signals:

protected:
  virtual void keyPressEvent(QKeyEvent *event);

public slots:

};

#endif // MAINWINDOW_H

mainwindow.cpp
Код:
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
  setWindowTitle("Main Window");
  setGeometry ( 20, 20, 800, 480);

  chiOfBasicMenu = new Basicmenu(this);
  chiOfBasicMenu -> setGeometry (0, 0, 800, 480);
}

void MainWindow::keyPressEvent(QKeyEvent *event)
{
  qDebug() << 1;
  switch (event->key())
  {
    case Qt::Key_A: chiOfBasicMenu->Highlightofrow(1);
      break;
    case Qt::Key_B: chiOfBasicMenu->Highlightofrow(2);
      break;
  }
  QMainWindow::keyPressEvent(event);
}

basicmenu.h
Код:
#ifndef BASICMENU_H
#define BASICMENU_H

#include "cell.h"

class Basicmenu : public QWidget
{
  Q_OBJECT
public:
  Basicmenu (QWidget *parent = 0);
  void Highlightofrow(int numberOfRow);
  virtual void KeyPressEvent(QKeyEvent *event);

  QGroupBox *borderOfMainMenu;
  Cell *cellOfArray[5][4];

public slots:

};
#endif

basicmenu.cpp
Код:
#include "basicmenu.h"

Basicmenu::Basicmenu(QWidget *parent)
  :QWidget(parent)
{
  borderOfMainMenu = new QGroupBox(this);
  borderOfMainMenu -> setGeometry ( 0, 0, 800, 480);
  borderOfMainMenu -> setStyleSheet("background-color: #0821FF;");

  for (int i=0; i<5; i++)
  {
    for (int j=0; j<4; j++)
    {
      cellOfArray[i][j] = new Cell(borderOfMainMenu);
      cellOfArray[i][j] -> setGeometry( (40*(j+1)+150*j), (30*(i+1)+60*i), 150, 60);
    }
  }
}

void Basicmenu::Highlightofrow(int numberOfRow)
{
  for (int i=0; i<5; i++)
  cellOfArray[i][numberOfRow] -> borderOfCell -> setFrameStyle(QFrame::WinPanel | QFrame::Sunken);
}

void Basicmenu::KeyPressEvent(QKeyEvent *event)
{
  qDebug() << 2;
  QWidget::keyPressEvent(event);
}

cell.h
Код:
#ifndef CELL_H
#define CELL_H

#include <QtCore>
#include <QtGui>

class Cell : public QWidget
{
public:
  Cell(QWidget *parent = 0);
  QFrame *borderOfCell;
  QLabel *nameOfCell;
  QCheckBox *visibilityOfCell;
  QVBoxLayout *placingInCell;
  virtual void keyPressEvent(QKeyEvent *event);
};
#endif

cell.cpp
Код:
#include "cell.h"

Cell::Cell(QWidget *parent)
  :QWidget(parent)
{
  borderOfCell = new QFrame(this);
  borderOfCell -> setFrameStyle(QFrame::WinPanel | QFrame::Raised);
  borderOfCell -> setStyleSheet("color: #F4FF23;" "background-color: #4356FF;");
  placingInCell = new QVBoxLayout;
  nameOfCell = new QLabel(borderOfCell);
  visibilityOfCell = new QCheckBox(borderOfCell);
  placingInCell -> addWidget(nameOfCell, 0, Qt::AlignCenter);
  placingInCell -> addWidget(visibilityOfCell, 0, Qt::AlignCenter);
  borderOfCell ->setLayout(placingInCell);
  borderOfCell-> setGeometry (0, 0, 150, 60);
}

void Cell::keyPressEvent(QKeyEvent *event)
{
  qDebug() << 3;
  QWidget::keyPressEvent(event);
}

При нажатии клавишь в дебаг будет выводиться
----------
3
1
----------
Но "2" (признак попадания в объект Basicmenu) не будет.
Записан
begin
Гость
« Ответ #8 : Август 05, 2010, 06:17 »

Но насколько я понимаю, это всего лишь доказывает, что Basicmenu не получает событие нажатия кнопки. Но при этом не решает мою проблему.
Так как же ее решить?
Записан
Anarion
Гость
« Ответ #9 : Август 05, 2010, 10:12 »

Я предложил же здесь решение.
1) Наследуешься от QMainWindow.
2) В унаследованном классе создаешь объект класса Basicmenu

Код:
class MainWindow : public QMainWindow
{
  Q_OBJECT

public:
  MainWindow(QWidget *parent = 0);
  /*!!!*/Basicmenu *chiOfBasicMenu;

3) Дальше все также как делал ты. События изначально попадают в объекты класса Cell, там не обрабатываются и отсылаются в виджет верхнего уровня, т.е. в объект класса MainWindow (унаследованный). И уже тут, поскольку в классе MainWindow есть объект класса Basicmenu, вызываешь необходимые методы его же:
Код:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
  qDebug() << 1;
  switch (event->key())
  {
    case Qt::Key_A: chiOfBasicMenu->Highlightofrow(1);
      break;
    case Qt::Key_B: chiOfBasicMenu->Highlightofrow(2);
      break;
  }
  QMainWindow::keyPressEvent(event);
}

Также ты создаешь объекты класса Cell внутри QGroupBox. Возможно он перехватывает сообщения и не отправляет дальше.
Записан
begin
Гость
« Ответ #10 : Август 05, 2010, 10:38 »

Спасибо большое за ответы. Разобрался с фильтрами событий и сделал через него. Будет свободное время - попробую ваш вариант. Еще разх спасибо за помощь.
Записан
SASA
Гость
« Ответ #11 : Август 05, 2010, 11:54 »

Цитировать
Насчет "магических констант" - а чем плохо их использовать?
Сравните Qt::Key_A и  0x41. Что более понятно?


Записан
begin
Гость
« Ответ #12 : Август 05, 2010, 13:54 »

Цитировать
Насчет "магических констант" - а чем плохо их использовать?
Сравните Qt::Key_A и  0x41. Что более понятно?
Согласен.  Исходя из этих соображений конечно понятней.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.067 секунд. Запросов: 21.