Align checkable items in qTableWidget
Asked Answered
B

3

6

In tableWidget I have one column entirely made up of checkable items. I can't figure out how to center the checkbox or at least remove the text-box next to it. As you can see on this picture enter image description here text-box has that ugly outline when I click on cell, I would like that turned off in entire table if it's possible. I've read that I need to use a delegates to control the positioning of items/icons, but for nooby like me it would take too long to understand that right, so if there is some simple solution that will make that column less ugly, please, examples would be appreciated.

Bani answered 26/4, 2013 at 13:28 Comment(2)
I think that the only way - is to implement custom "checkbox only" delegate for second column. It is very easy to draw checkbox and remove selection frame there. I can provide C++ sample, if it necessary.Marcmarcano
@DmitrySazonov I've solved selection frame problem, but if you have c++ example that shows how to use delegate for checkbox item alignment in specific column, please post it as an answer.Bani
E
5

That rectangle is a focus recangle and cannot be hidden via an stylesheet.

Edit: So you have four options:

1 - It seems that u can use

 tablewidget->setFocusPolicy(Qt::NoFocus);

But you will lose the ability to process keyboard events. See FocusPolicy

2 - Set the checkable widgetitems as disabled, not selectable through setFlags. I don't know if this is a bug, but in my Qt i will be alowed to still click on checkboxes

3 - Set your first column as checkable though setFlags too, and just dont use that second column. Checkboxes will be shown in same column that the Strings but at left.

4- That custom delegate you dont want to create.

And you got here an example

Electrotype answered 29/4, 2013 at 10:45 Comment(1)
1 - tableWidget.setFocusPolicy(QtCore.Qt.NoFocus) helps with focus border (I have only mouse events in table, so tnx for that) 2 - Can't do with Python. setCheckState is not working, I need it to be done automaticaly in some cases 3 - Can't do. I have few columns with checkboxes and I need them separated. 4 - delegate from example removes focus (solved in item no. 1), can you give me example where it's used for alignment?Bani
L
13

An example that worked using pyqt4. Adapted from falsinsoft

qcheck box centre inside pyqt4 atble widget

table = QTableWidget()   
cell_widget = QWidget()
chk_bx = QCheckBox()
chk_bx.setCheckState(Qt.Checked)
lay_out = QHBoxLayout(cell_widget)
lay_out.addWidget(chk_bx)
lay_out.setAlignment(Qt.AlignCenter)
lay_out.setContentsMargins(0,0,0,0)
cell_widget.setLayout(lay_out)
tableWidget.setCellWidget(i, 0, cell_widget)
Lair answered 10/5, 2015 at 12:49 Comment(0)
M
7

Usage:

pView->setItemDelegateForColumn( 1, new DELEGATE::CheckBoxDelegate( this ) );

CheckBoxDelegate.h

#ifndef CHECKBOXDELEGATE_H
#define CHECKBOXDELEGATE_H

#include <QStyledItemDelegate>
#include <QModelIndex>


namespace DELEGATE
{

    class CheckBoxDelegate
        : public QStyledItemDelegate
    {
        Q_OBJECT

    public:
        CheckBoxDelegate( QObject *parent );
        ~CheckBoxDelegate();

        void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
        bool editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index );

    private:
        QModelIndex m_lastClickedIndex;
    };

}


#endif // CHECKBOXDELEGATE_H

CheckBoxDelegate.cpp

#include "CheckBoxDelegate.h"

#include <QApplication>
#include <QStyleOptionButton>
#include <QPainter>
#include <QEvent>
#include <QMouseEvent>


namespace DELEGATE
{

    CheckBoxDelegate::CheckBoxDelegate( QObject *parent )
        : QStyledItemDelegate( parent )
    {
    }

    CheckBoxDelegate::~CheckBoxDelegate()
    {
    }

    void CheckBoxDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
    {
        // Setting parameters
        Qt::CheckState state = (Qt::CheckState)index.data( Qt::CheckStateRole ).toInt();
        QStyleOptionButton opt;

        opt.state = QStyle::State_Enabled; // CheckBox enabled
        if ( option.state & QStyle::State_MouseOver )
            opt.state |= QStyle::State_MouseOver; // Mouse over sell
        switch ( state )  // Check box state
        {
        case Qt::Unchecked:
            opt.state |= QStyle::State_Off;
            break;
        case Qt::PartiallyChecked:
            opt.state |= QStyle::State_NoChange;
            break;
        case Qt::Checked:
            opt.state |= QStyle::State_On;
            break;
        }
        // Check box rect
        opt.rect = QApplication::style()->subElementRect( QStyle::SE_CheckBoxIndicator, &opt, NULL );
        const int x = option.rect.center().x() - opt.rect.width() / 2;
        const int y = option.rect.center().y() - opt.rect.height() / 2;
        opt.rect.moveTo( x, y );

        // Optional: draw hover focus
        if ( option.state & QStyle::State_MouseOver )
            painter->fillRect( option.rect, QBrush( QColor( 0xff, 0xff, 0xaa, 0x60 ) ) );

        // Mandatory: drawing check box
        QApplication::style()->drawControl( QStyle::CE_CheckBox, &opt, painter );
    }

    bool CheckBoxDelegate::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index )
    {
        switch ( event->type() )
        {
        case QEvent::MouseButtonPress:
            m_lastClickedIndex = index;
            break;

        case QEvent::MouseButtonRelease:
            {
                if ( index != m_lastClickedIndex )
                    break;
                QMouseEvent *e = static_cast< QMouseEvent * >( event );
                if ( e->button() != Qt::LeftButton )
                    break;
                m_lastClickedIndex = QModelIndex();

                QStyleOptionButton opt;
                opt.rect = QApplication::style()->subElementRect( QStyle::SE_CheckBoxIndicator, &opt, NULL );
                const int x = option.rect.center().x() - opt.rect.width() / 2;
                const int y = option.rect.center().y() - opt.rect.height() / 2;
                opt.rect.moveTo( x, y );

                if ( opt.rect.contains( e->pos() ) )
                {
                    // TODO: process click on checkbox logic
                    Qt::CheckState state = (Qt::CheckState)index.data( Qt::CheckStateRole ).toInt();
                    switch ( state )
                    {
                    case Qt::Unchecked:
                        state = Qt::PartiallyChecked;
                        break;
                    case Qt::PartiallyChecked:
                        state = Qt::Checked;
                        break;
                    case Qt::Checked:
                        state = Qt::Unchecked;
                        break;
                    }

                    model->setData( index, state, Qt::CheckStateRole );
                }
                return true;
            }

        default:
            break;
        }

        return QAbstractItemDelegate::editorEvent( event, model, option, index );
    }

}

Sample:

sample

Subjects to improve:

  • Selection drawing
  • Mouse hover processing
  • Double click processing
  • Keyboard edit events // there are a lot of examples in google, stackoverflow

Note: your model should process setData method for Qt::CheckStateRole role.

Marcmarcano answered 30/4, 2013 at 13:37 Comment(2)
I guess that's it. Didn't have time to translate it to python but it seems legit. Bounty is yoursBani
Feel free to ask, if you'll have additional questions.Marcmarcano
E
5

That rectangle is a focus recangle and cannot be hidden via an stylesheet.

Edit: So you have four options:

1 - It seems that u can use

 tablewidget->setFocusPolicy(Qt::NoFocus);

But you will lose the ability to process keyboard events. See FocusPolicy

2 - Set the checkable widgetitems as disabled, not selectable through setFlags. I don't know if this is a bug, but in my Qt i will be alowed to still click on checkboxes

3 - Set your first column as checkable though setFlags too, and just dont use that second column. Checkboxes will be shown in same column that the Strings but at left.

4- That custom delegate you dont want to create.

And you got here an example

Electrotype answered 29/4, 2013 at 10:45 Comment(1)
1 - tableWidget.setFocusPolicy(QtCore.Qt.NoFocus) helps with focus border (I have only mouse events in table, so tnx for that) 2 - Can't do with Python. setCheckState is not working, I need it to be done automaticaly in some cases 3 - Can't do. I have few columns with checkboxes and I need them separated. 4 - delegate from example removes focus (solved in item no. 1), can you give me example where it's used for alignment?Bani

© 2022 - 2024 — McMap. All rights reserved.