From 71b7806f036b262742dd29d3f36b3f98c0b7ef5e Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Thu, 15 Oct 2015 11:42:59 +0200 Subject: [PATCH] Delay applying a changed filter value When changing a filter value delay the application of the new value on the table for a couple of milliseconds. This makes the filter process much smoother for fast typing users working on large tables. See issue #415. --- CMakeLists.txt | 2 ++ src/FilterLineEdit.cpp | 70 +++++++++++++++++++++++++++++++++++++++ src/FilterLineEdit.h | 36 ++++++++++++++++++++ src/FilterTableHeader.cpp | 42 ++--------------------- src/src.pro | 6 ++-- 5 files changed, 114 insertions(+), 42 deletions(-) create mode 100644 src/FilterLineEdit.cpp create mode 100644 src/FilterLineEdit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f218bda..6da47663 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,7 @@ set(SQLB_MOC_HDR src/SqlUiLexer.h src/FileDialog.h src/ColumnDisplayFormatDialog.h + src/FilterLineEdit.h ) set(SQLB_SRC @@ -118,6 +119,7 @@ set(SQLB_SRC src/SqlUiLexer.cpp src/FileDialog.cpp src/ColumnDisplayFormatDialog.cpp + src/FilterLineEdit.cpp ) set(SQLB_FORMS diff --git a/src/FilterLineEdit.cpp b/src/FilterLineEdit.cpp new file mode 100644 index 00000000..96a297a1 --- /dev/null +++ b/src/FilterLineEdit.cpp @@ -0,0 +1,70 @@ +#include "FilterLineEdit.h" + +#include +#include + +FilterLineEdit::FilterLineEdit(QWidget* parent, QList* filters, int columnnum) : QLineEdit(parent), filterList(filters), columnNumber(columnnum) +{ + setPlaceholderText(tr("Filter")); +#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) + setClearButtonEnabled(true); +#endif + setProperty("column", columnnum); // Store the column number for later use + + // Introduce a timer for delaying the signal triggered whenever the user changes the filter value. + // The idea here is that the textChanged() event isn't connected to the update filter slot directly anymore + // but instead there this timer mechanism in between: whenever the user changes the filter the delay timer + // is (re)started. As soon as the user stops typing the timer has a chance to trigger and call the + // delayedSignalTimerTriggered() method which then stops the timer and emits the delayed signal. + delaySignalTimer = new QTimer(this); + delaySignalTimer->setInterval(300); // This is the milliseconds of not-typing we want to wait before triggering + connect(this, SIGNAL(textChanged(QString)), delaySignalTimer, SLOT(start())); + connect(delaySignalTimer, SIGNAL(timeout()), this, SLOT(delayedSignalTimerTriggered())); + + // Immediately emit the delayed filter value changed signal if the user presses the enter or the return key or + // the line edit widget loses focus + connect(this, SIGNAL(editingFinished()), this, SLOT(delayedSignalTimerTriggered())); +} + +void FilterLineEdit::delayedSignalTimerTriggered() +{ + // Stop the timer first to avoid triggering in intervals + delaySignalTimer->stop(); + + // Emit the delayed signal using the current value + emit delayedTextChanged(text()); +} + +void FilterLineEdit::keyReleaseEvent(QKeyEvent* event) +{ + if(event->key() == Qt::Key_Tab) + { + if(columnNumber < filterList->size() - 1) + { + filterList->at(columnNumber + 1)->setFocus(); + event->accept(); + } + } else if(event->key() == Qt::Key_Backtab) { + if(columnNumber > 0) + { + filterList->at(columnNumber - 1)->setFocus(); + event->accept(); + } + } +} + +void FilterLineEdit::clear() +{ + // When programatically clearing the line edit's value make sure the effects are applied immediately, i.e. + // bypass the delayed signal timer + QLineEdit::clear(); + delayedSignalTimerTriggered(); +} + +void FilterLineEdit::setText(const QString& text) +{ + // When programatically setting the line edit's value make sure the effects are applied immediately, i.e. + // bypass the delayed signal timer + QLineEdit::setText(text); + delayedSignalTimerTriggered(); +} diff --git a/src/FilterLineEdit.h b/src/FilterLineEdit.h new file mode 100644 index 00000000..b1d9fe13 --- /dev/null +++ b/src/FilterLineEdit.h @@ -0,0 +1,36 @@ +#ifndef FILTERLINEEDIT_H +#define FILTERLINEEDIT_H + +#include +#include + +class QTimer; +class QKeyEvent; + +class FilterLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + explicit FilterLineEdit(QWidget* parent, QList* filters, int columnnum); + + // Override methods for programatically changing the value of the line edit + void clear(); + void setText(const QString& text); + +private slots: + void delayedSignalTimerTriggered(); + +signals: + void delayedTextChanged(QString text); + +protected: + void keyReleaseEvent(QKeyEvent* event); + +private: + QList* filterList; + int columnNumber; + QTimer* delaySignalTimer; +}; + +#endif diff --git a/src/FilterTableHeader.cpp b/src/FilterTableHeader.cpp index b3aee5a4..bcbbcac0 100644 --- a/src/FilterTableHeader.cpp +++ b/src/FilterTableHeader.cpp @@ -1,46 +1,8 @@ #include "FilterTableHeader.h" +#include "FilterLineEdit.h" -#include #include #include -#include -#include - -class FilterLineEdit : public QLineEdit -{ -public: - explicit FilterLineEdit(QWidget* parent, QList* filters, int columnnum) : QLineEdit(parent), filterList(filters), columnNumber(columnnum) - { - setPlaceholderText(tr("Filter")); -#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) - setClearButtonEnabled(true); -#endif - setProperty("column", columnnum); // Store the column number for later use - } - -protected: - void keyReleaseEvent(QKeyEvent* event) - { - if(event->key() == Qt::Key_Tab) - { - if(columnNumber < filterList->size() - 1) - { - filterList->at(columnNumber + 1)->setFocus(); - event->accept(); - } - } else if(event->key() == Qt::Key_Backtab) { - if(columnNumber > 0) - { - filterList->at(columnNumber - 1)->setFocus(); - event->accept(); - } - } - } - -private: - QList* filterList; - int columnNumber; -}; FilterTableHeader::FilterTableHeader(QTableView* parent) : QHeaderView(Qt::Horizontal, parent) @@ -78,7 +40,7 @@ void FilterTableHeader::generateFilters(int number, bool showFirst) l->setVisible(false); else l->setVisible(true); - connect(l, SIGNAL(textChanged(QString)), this, SLOT(inputChanged(QString))); + connect(l, SIGNAL(delayedTextChanged(QString)), this, SLOT(inputChanged(QString))); filterWidgets.push_back(l); } diff --git a/src/src.pro b/src/src.pro index 5d18b040..eac58882 100644 --- a/src/src.pro +++ b/src/src.pro @@ -52,7 +52,8 @@ HEADERS += \ ExportSqlDialog.h \ SqlUiLexer.h \ FileDialog.h \ - ColumnDisplayFormatDialog.h + ColumnDisplayFormatDialog.h \ + FilterLineEdit.h SOURCES += \ sqlitedb.cpp \ @@ -80,7 +81,8 @@ SOURCES += \ ExportSqlDialog.cpp \ SqlUiLexer.cpp \ FileDialog.cpp \ - ColumnDisplayFormatDialog.cpp + ColumnDisplayFormatDialog.cpp \ + FilterLineEdit.cpp RESOURCES += icons/icons.qrc \ translations/flags/flags.qrc \