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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Как отловить клик по вкладке QTabWidget?  (Прочитано 9910 раз)
maksimAstraLin
Гость
« : Август 22, 2017, 14:22 »

Здравствуйте.

Подскажите, пожалуйста, как отловить событие нажатия левой кнопкой мыши по вкладкам
QtabWidget?

Хочу реализовать drag and drop для вкладок. Если вешать его на нажатие правой кнопкой мыши - работает, а отловить событие нажатия левой кнопкой мыши не получается. Похоже, оно где-то перехватывается и не доходит до класса основного окна.

С уважением, Максим.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #1 : Август 22, 2017, 15:30 »

http://doc.qt.io/qt-5/qtabbar.html#tabBarClicked не подходит?
Записан
maksimAstraLin
Гость
« Ответ #2 : Август 22, 2017, 15:37 »

К сожалению, не могу использовать эту функцию. Она появилась только в Qt 5.2, а у меня Qt 4.8 . Прошу прощения, что не указал этого сразу.
Записан
Bepec
Гость
« Ответ #3 : Август 22, 2017, 15:43 »

Ставь eventfilter, лови событие нажатия. Ну проще выражаясь реализуй сигнал tabClicked сам Улыбающийся
Записан
maksimAstraLin
Гость
« Ответ #4 : Август 22, 2017, 15:52 »

Подскажите, пожалуйста, что я мог упустить. Мой фильтр не отлавливает нажатие левой кнопкой мыши по "закладке" вкладки QTabWidget'а. Вот мой код фильтра:
Код:
bool MainWindow::eventFilter( QObject *watched, QEvent *event ) {
    std::cerr << "\nIn MainWindow::eventFilter()\n";

    if ( event->type() == QEvent::MouseButtonPress ) {
        std::cerr << "event->type()==MouseButtonPress\n";
        if ( QApplication::mouseButtons() & Qt::LeftButton ) {
            if ( is_over_tabBar ) {
                int index = -1;
                QTabBar *tab_bar = ui->tabWidget->findChild<QTabBar*>();
                if ( tab_bar ) {
                    QPoint tab_pos = tab_bar->mapToGlobal( QPoint(0,0) );
                    index = tab_bar->tabAt( QCursor::pos() - tab_pos );
                }
                emit mouseClickedOverTabBar( index );
            }
        }
    }

    QTabBar *tab_bar = ui->tabWidget->findChild<QTabBar*>();
    if ( tab_bar ) {
        QPoint tab_pos = tab_bar->mapToGlobal( QPoint(0,0) );
        int tab_x = tab_pos.x();
        int tab_y = tab_pos.y();
        int tab_width = tab_bar->width();
        int tab_height = tab_bar->height();
        QRect tab_rect( tab_x, tab_y, tab_width, tab_height );
        if ( tab_rect.contains( QCursor::pos() ) ) {
            is_over_tabBar = true;
        }
        else {
            is_over_tabBar = false;
        }
    }

    return QMainWindow::eventFilter( watched, event );
}

Насколько я понимаю, когда я тыкаю на "закладку" вкладки, то включается какой-то другой обработчик, который в том числе занимается перемещением вкладок между собой. Этот обработчик, по-моему, срабатывает до того, как событие доберется до моего фильтра. Этот обработчик возвращает true - типа, "событие отработано" - и дальше оно не распространяется.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Август 22, 2017, 16:43 »

Снимите "трассу событий", тогда не придется гадать. Вешаете фильтр на qApp.
Код
C++ (Qt)
bool MyAppFilter::eventFilter( QObject * object, QEvent * event )
{
  static int count = 0;
  if (!CapsLockPreessed()) return false;  // желательно
 
  switch (event->type()) {
     case QEvent::Timer:
     case QEvent::MouseMove:    // чтобы слишком не сорить в консоли
       break;
     default:
       qDebug() << ++count << object << event->type();
  }
  return false;
}
Записан
maksimAstraLin
Гость
« Ответ #6 : Август 22, 2017, 17:21 »

Igors, разъясните, пожалуйста, чайнику...

Я понял, что qApp - это некий глобальный указатель на объект текущего приложения. Но не понимаю, как повесить на него фильтр. Когда передаю этот указатель в installEventFilter( qApp ), то eventFilter не срабатывает ни разу.
Ваш класс - MyAppFilter - это чей потомок? Потомок QMainWindow?
А еще не понимаю, как реализовать CapsLockPressed()...
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #7 : Август 22, 2017, 17:49 »

А как вам такой вариант ещё?
Наследоваться от QTabBar, добавить слот tabBarClicked(int) по аналогии с Qt5.2
Код
C++ (Qt)
void QTabBar::mousePressEvent(QMouseEvent *event)
{
   Q_D(QTabBar);
 
   const QPoint pos = event->pos();
   const bool isEventInCornerButtons = (!d->leftB->isHidden() && d->leftB->geometry().contains(pos))
                                    || (!d->rightB->isHidden() && d->rightB->geometry().contains(pos));
   if (!isEventInCornerButtons) {
       const int index = d->indexAtPos(pos);
       emit tabBarClicked(index);
   }
Также наследоваться от QTabWidget и в его конструкторе вызвать [protected] void QTabWidget::setTabBar(QTabBar *tb).
Кажется, должно сработать.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Август 23, 2017, 08:02 »

Я понял, что qApp - это некий глобальный указатель на объект текущего приложения. Но не понимаю, как повесить на него фильтр. Когда передаю этот указатель в installEventFilter( qApp ), то eventFilter не срабатывает ни разу.
Ваш класс - MyAppFilter - это чей потомок? Потомок QMainWindow?
Любой потомок QObject
Код
C++ (Qt)
class MyAppFilter : public QObject {
public:
 MyAppFilter( QObject * parent ) : QObject(parent)
 {
 }
 
 bool eventFilter( QObject * object, QEvent * event )
 {
   ... // код выше
 }
};
 
// Использование
qApp->installEvenrFilter(new MyEventFilter(qApp));

А еще не понимаю, как реализовать CapsLockPressed()...
Нвсколько я знаю, в Qt нет средств чтобы определить что сейчас клавиша нажата и удерживается. Поэтому я делал нативными средствами. Для Вындоуз ф-ция GetAsyncKeyState. Это для удобства, чтобы в консоль постоянно не лилось
« Последнее редактирование: Август 23, 2017, 08:43 от Igors » Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #9 : Август 24, 2017, 06:08 »

Не стоит вешать фильтр событий на всё приложение, оно принимает слишком много событий
Записан

Юра.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Август 24, 2017, 07:12 »

Не стоит вешать фильтр событий на всё приложение, оно принимает слишком много событий
Поэтому и нужна возможность его вкл/выкл клавишей
Записан
maksimAstraLin
Гость
« Ответ #11 : Август 24, 2017, 12:03 »

Благодарю всех за помощь! Думаю, можно считать задачу решенной.

Igors, до реализации CapsLockPreessed() я не добрался, но, повесив eventFilter на qApp, благодаря qDebug(), я всё же смог выловить, что при клике по "закладке" вкладки происходит 2 события MouseButtonPress: одно для QWidgetWindow, другое - для QTabBar. Тогда я повесил eventFilter на
Код:
    QTabBar *tab_bar = ui->tabWidget->findChild<QTabBar*>();
    tab_bar->installEventFilter( this );
Сделал, чтобы фильтр, при соблюдении необходимых условий, вызывал функцию tabBarClicked( int index ) и все заработало:
Код:
bool MainWindow::eventFilter( QObject *watched, QEvent *event ) {
    QTabBar *tab_bar = ui->tabWidget->findChild<QTabBar*>();
    if ( watched == tab_bar && event->type() == QEvent::MouseButtonPress ) {
        if ( QApplication::mouseButtons() == Qt::LeftButton ) {
            QPoint tab_pos = tab_bar->mapToGlobal( QPoint(0,0) );
            int tab_x = tab_pos.x();
            int tab_y = tab_pos.y();
            int tab_width = tab_bar->width();
            int tab_height = tab_bar->height();
            QRect tab_rect( tab_x, tab_y, tab_width, tab_height );
            if ( tab_rect.contains( QCursor::pos() ) ) {
                int index = tab_bar->tabAt( QCursor::pos() - tab_pos );
                tabBarClicked( index );
            }
        }
    }
    if ( moving ) {
        if ( QApplication::mouseButtons() & Qt::LeftButton ) {
            dragCurrentPosition = QCursor::pos();
            if ( already_need_to_drag_the_tab() ) {
                perform_drag_operation();
                moving = false;
            }
        }
        else {
            moving = false;
        }
    }
    return QMainWindow::eventFilter( watched, event );
}

__Heaven__, попробовал реализовать предложенный Вами вариант с наследованием от QTabBar и QTabWidget, но опыта не хватило сделать также элегантно, как в Вашем коде. Я не знаком с использованием D-Pointer, поэтому пробовал без него. Создал в классе MyTabBar : public QTabBar сигнал tabBar_mouseLeftButtonClicked( int index ) и добавил emit этого сигнала в обработчик события MyTabBar::mousePressEvent(QMouseEvent *event).
В конструкторе класса MyTabWidget : public QTabWidget я связал сигнал MyTabBar'а со слотом MainWindow::tabBarClicked(int index):
Код:
MyTabWidget::MyTabWidget(QWidget *parent) :
    QTabWidget( parent )
{
    MyTabBar *tab_bar = new MyTabBar( parent );
    tab_bar->addTab( "One" );
    tab_bar->addTab( "Two" );
    tab_bar->addTab( "Three" );
    this->setTabBar( tab_bar );

    connect( tab_bar, SIGNAL( tabBar_mouseLeftButtonClicked(int) ), parent, SLOT( tabBarClicked(int) ) );
}
Теперь при клике на "закладке" вкладки срабатывает этот слот.
Записан
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #12 : Август 24, 2017, 15:38 »

Код, что я предоставил, не мой. Это кусок из исходников qt. Посыл был сделать по аналогии Улыбающийся
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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