QT通过单击和拖动检查多个框
QT Checking multiple boxes with click and drag
所以我想弄清楚您将如何着手制作它,您可以在 QListView 中单击一个复选框并将鼠标(仍然单击)拖动到多个复选框上,它也会选中它们。因为现在我必须单击要选中的所有复选框,如果我需要连续选中多个复选框,我更愿意在此处单击并拖动到我需要选中的最后一个。
我也不是指 select all 方法,我只需要说在 100 个复选框中可能有 25 个连续我需要检查,并且不想一次检查所有这些时间.
您可以使用自定义委托来监视鼠标 clicks/moves 并对您的模型数据采取行动。
带有列表视图和一系列复选框的基本 window:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),
m_model(new QStandardItemModel(9, 2))
{
ui->setupUi(this);
for (int row = 0; row < m_model->rowCount(); ++row) {
QStandardItem *Item = new QStandardItem();
Item->setCheckable( true );
Item->setCheckState( Qt::Checked );
m_model->setItem(row, Item);
}
ui->listView->setItemDelegateForColumn(0, new CustomDelegate(this));
ui->listView->setModel(m_model);
}
带有绘画事件的自定义委托(将其替换为您当前绘制复选框的方式)和 editorEvent。
在 `editorEvent` 中,在 `MouseButtonPress` 上,我们根据需要 check/uncheck 框,然后记住我们是在选中还是取消选中以在 `MouseMove` 中参考。
然后在 `MouseMove` 中,我们 check/uncheck 框越过它们。
CustomDeletage.h
#ifndef CUSTOMDELEGATE_H
#define CUSTOMDELEGATE_H
#include <QApplication>
#include <QEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QStyledItemDelegate>
class CustomDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
CustomDelegate(QObject *parent );
void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
Q_ASSERT(index.isValid());
// Get value from model.
bool state = index.data( Qt::DisplayRole ).toInt();
QStyleOptionButton optBtn;
optBtn.state = QStyle::State_Enabled; // CheckBox enabled
if ( option.state & QStyle::State_MouseOver )
optBtn.state |= QStyle::State_MouseOver; // Mouse over cell
// If value is true - checked box, otherwise - unchecked box.
if(state) {
optBtn.state |= QStyle::State_On;
} else {
optBtn.state |= QStyle::State_Off;
}
// Check box rect, centered.
optBtn.rect = QApplication::style()->subElementRect( QStyle::SE_CheckBoxIndicator, &optBtn, Q_NULLPTR );
const int x = option.rect.center().x() - optBtn.rect.width() / 2;
const int y = option.rect.center().y() - optBtn.rect.height() / 2;
optBtn.rect.moveTo( x, y );
// Draw the background color.
if (option.state & QStyle::State_Selected && option.state & QStyle::State_Active)
painter->fillRect(option.rect, option.palette.highlight());
else if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.background());
// Draw the check box.
QApplication::style()->drawControl( QStyle::CE_CheckBox, &optBtn, painter );
}
bool editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
{
Q_UNUSED(option)
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
// Do nothing if edit model is not editable.
Qt::ItemFlags flags = model->flags(index);
if(! flags.testFlag(Qt::ItemIsEditable) ) break;
// Only accept left clicks.
QMouseEvent *e = static_cast< QMouseEvent * >( event );
if ( e->button() != Qt::LeftButton ) break;
// Invert the current value.
bool currentValue = model->data(index, Qt::DisplayRole).toBool();
model->setData(index, !currentValue, Qt::EditRole);
// Set the process as either checking, or unchecking.
currentValue ? m_checkingOrUnchecking = 2 : m_checkingOrUnchecking = 1;
break;
}
case QEvent::MouseMove:
{
// Do nothing if edit model is not editable.
Qt::ItemFlags flags = model->flags(index);
if(! flags.testFlag(Qt::ItemIsEditable) ) break;
// If we are at the same index as the last time, break so we do not continuously invert the state of a single check box.
if (index == m_lastPassedOverIndex) break;
// If mouse is moved while clicked, set the box we pass over to the current checking or unchecking state.
if(m_checkingOrUnchecking == 1) {
model->setData(index, true, Qt::EditRole);
} else if(m_checkingOrUnchecking == 2) {
model->setData(index, false, Qt::EditRole);
}
// Make sure we are not double-inverting an index.
m_lastPassedOverIndex = index;
break;
}
case QEvent::MouseButtonRelease:
{
m_checkingOrUnchecking = 0;
break;
}
default:
break;
}
return true;
}
private:
QModelIndex m_lastPassedOverIndex; // The index last passed over, so while clicking over a check box, we do not continupusly invert its state.
int m_checkingOrUnchecking = 0; // Is the user currently checking, or unchecking boxes? 0 = do nothing, 1 = checking, 2 = unchecking.
};
#endif // CUSTOMDELEGATE_H
所以我想弄清楚您将如何着手制作它,您可以在 QListView 中单击一个复选框并将鼠标(仍然单击)拖动到多个复选框上,它也会选中它们。因为现在我必须单击要选中的所有复选框,如果我需要连续选中多个复选框,我更愿意在此处单击并拖动到我需要选中的最后一个。
我也不是指 select all 方法,我只需要说在 100 个复选框中可能有 25 个连续我需要检查,并且不想一次检查所有这些时间.
您可以使用自定义委托来监视鼠标 clicks/moves 并对您的模型数据采取行动。
带有列表视图和一系列复选框的基本 window:
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),
m_model(new QStandardItemModel(9, 2))
{
ui->setupUi(this);
for (int row = 0; row < m_model->rowCount(); ++row) {
QStandardItem *Item = new QStandardItem();
Item->setCheckable( true );
Item->setCheckState( Qt::Checked );
m_model->setItem(row, Item);
}
ui->listView->setItemDelegateForColumn(0, new CustomDelegate(this));
ui->listView->setModel(m_model);
}
带有绘画事件的自定义委托(将其替换为您当前绘制复选框的方式)和 editorEvent。
在 `editorEvent` 中,在 `MouseButtonPress` 上,我们根据需要 check/uncheck 框,然后记住我们是在选中还是取消选中以在 `MouseMove` 中参考。
然后在 `MouseMove` 中,我们 check/uncheck 框越过它们。
CustomDeletage.h
#ifndef CUSTOMDELEGATE_H
#define CUSTOMDELEGATE_H
#include <QApplication>
#include <QEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QStyledItemDelegate>
class CustomDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
CustomDelegate(QObject *parent );
void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{
Q_ASSERT(index.isValid());
// Get value from model.
bool state = index.data( Qt::DisplayRole ).toInt();
QStyleOptionButton optBtn;
optBtn.state = QStyle::State_Enabled; // CheckBox enabled
if ( option.state & QStyle::State_MouseOver )
optBtn.state |= QStyle::State_MouseOver; // Mouse over cell
// If value is true - checked box, otherwise - unchecked box.
if(state) {
optBtn.state |= QStyle::State_On;
} else {
optBtn.state |= QStyle::State_Off;
}
// Check box rect, centered.
optBtn.rect = QApplication::style()->subElementRect( QStyle::SE_CheckBoxIndicator, &optBtn, Q_NULLPTR );
const int x = option.rect.center().x() - optBtn.rect.width() / 2;
const int y = option.rect.center().y() - optBtn.rect.height() / 2;
optBtn.rect.moveTo( x, y );
// Draw the background color.
if (option.state & QStyle::State_Selected && option.state & QStyle::State_Active)
painter->fillRect(option.rect, option.palette.highlight());
else if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.background());
// Draw the check box.
QApplication::style()->drawControl( QStyle::CE_CheckBox, &optBtn, painter );
}
bool editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
{
Q_UNUSED(option)
switch ( event->type() )
{
case QEvent::MouseButtonPress:
{
// Do nothing if edit model is not editable.
Qt::ItemFlags flags = model->flags(index);
if(! flags.testFlag(Qt::ItemIsEditable) ) break;
// Only accept left clicks.
QMouseEvent *e = static_cast< QMouseEvent * >( event );
if ( e->button() != Qt::LeftButton ) break;
// Invert the current value.
bool currentValue = model->data(index, Qt::DisplayRole).toBool();
model->setData(index, !currentValue, Qt::EditRole);
// Set the process as either checking, or unchecking.
currentValue ? m_checkingOrUnchecking = 2 : m_checkingOrUnchecking = 1;
break;
}
case QEvent::MouseMove:
{
// Do nothing if edit model is not editable.
Qt::ItemFlags flags = model->flags(index);
if(! flags.testFlag(Qt::ItemIsEditable) ) break;
// If we are at the same index as the last time, break so we do not continuously invert the state of a single check box.
if (index == m_lastPassedOverIndex) break;
// If mouse is moved while clicked, set the box we pass over to the current checking or unchecking state.
if(m_checkingOrUnchecking == 1) {
model->setData(index, true, Qt::EditRole);
} else if(m_checkingOrUnchecking == 2) {
model->setData(index, false, Qt::EditRole);
}
// Make sure we are not double-inverting an index.
m_lastPassedOverIndex = index;
break;
}
case QEvent::MouseButtonRelease:
{
m_checkingOrUnchecking = 0;
break;
}
default:
break;
}
return true;
}
private:
QModelIndex m_lastPassedOverIndex; // The index last passed over, so while clicking over a check box, we do not continupusly invert its state.
int m_checkingOrUnchecking = 0; // Is the user currently checking, or unchecking boxes? 0 = do nothing, 1 = checking, 2 = unchecking.
};
#endif // CUSTOMDELEGATE_H