PDA

View Full Version : Custom itemClicked() for QTableWidget



Malorn44
11th March 2019, 15:02
I'm trying to create a custom class for QTableWidget where when clicking on a cell (or eventually just pressing the mouse down over a cell) it changes the background color.
This is what I have so far... it's fairly simple but it doesn't work yet and I'm not sure what I'm missing. Sorry, I'm new to the Qt environment.

Excerpt from mainwindow.cpp


int row = 10;
int col = 10;

// set the amount of rows and columns
ui->board->setRowCount(row);
ui->board->setColumnCount(col);

// remove table headers
ui->board->horizontalHeader()->setVisible(false);
ui->board->verticalHeader()->setVisible(false);

// table styling
ui->board->setFocusPolicy(Qt::NoFocus);
ui->board->setSelectionMode(QAbstractItemView::NoSelection);
// ui->board->setStyleSheet("selection-background-color: transparent");
ui->board->setEditTriggers(QAbstractItemView::NoEditTriggers) ;

// set fixed column and row width
for (int i = 0; i < row; i++)
ui->board->setRowHeight(i, 50);
for (int i = 0; i < col; i++)
ui->board->setColumnWidth(i, 50);

// populate with items
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
ui->board->setItem(i, j, new QTableWidgetItem);
}
}

excerpt from table.h


#include <QTableWidget>
class Table : public QTableWidget
{
public:
Table(QWidget *parent = nullptr) {}

Q_SIGNALS:
void itemClicked(QTableWidgetItem *item);


};

excerpt from table.cpp

#include "table.h"

void Table::itemClicked(QTableWidgetItem *item) {
item->setBackground(Qt::red);
}

anda_skoa
11th March 2019, 16:40
itemClicked() is a signal

If you want to react to a signal you connect it to a slot.
See QObject::connect().

Cheers,
_

Malorn44
11th March 2019, 19:31
I'm sorry. I'm a little confused as to how the connect works and how I'd put that into my code. Do I need to override anything?
What exactly do I need to include to modify the click behavior?

I was looking here: https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtablewidget.h.html and https://code.woboq.org/qt5/qtbase/src/widgets/itemviews/qtablewidget.cpp.html

To try and figure out how connect and the slot is used within the actual class but I can't figure it out.

Added after 1 14 minutes:

I think I do something like this:

Table::Table(QWidget *parent) {
connect(ui->board, SIGNAL(itemClicked(QTableWidgetItem*)),
this, SLOT(onItemClicked(QTableWidgetItem*)));
}

but I am having an error on ui (Use of undeclared identifier ui) and I'm not sure how to fix it.
Or if I am even doing this much correctly.

d_stranz
11th March 2019, 19:49
I am guessing that your variable "ui" is a private member of the MainWindow class, and that "ui->board" points to an instance of your Table widget. It is inaccessible from inside your Table class (or any other class besides MainWindow, for that matter).

I also guess that you don't actually need your Table class at all. You do not need to derive from QTableWidget in order to use signals generated by QTableWidget. If what you want to do is handle an itemClicked() signal generated by QTableWidget, then you should implement that as a slot in your MainWindow class and make the connection in the MainWindow constructor after you have called setupUi():



// MainWindow.h

class MainWindow : public QMainWindow
{
Q_OBJECT;

MainWindow( QWidget * parent );

// ...

private slots:
void onItemClicked( QTableWidgetItem * pItem );

// ...
};

// MainWindow.cpp

MainWindow::MainWindow( QWidget * parent )
: QMainWindow( parent )
// ...
{

// Do setup, then this (which uses the new, type-safe version of connect())

connect( ui->board, &QTableWidget::itemClicked, this, &MainWindow::onItemClicked );
}

void MainWindow::onItemClicked( QTableWidgetItem * pItem )
{
// Do whatever you want with the item (of course, after you have checked to see that pItem is not null)
}

Malorn44
12th March 2019, 13:41
Alright, I got that working. The next thing I need to do is to do the same thing as click when I drag my mouse over cells. I thought I might be able to accomplish this using itemPressed and itemEntered in unison but I'm not sure how to do this without making a boolean pressed to check if both conditions are satisfied. However, there isn't a release signal or anything. Can I do a normal mouse pressed then?

Edit: nevermind actually. Apparently itemEntered connected to the same slot was enough. I now have to connect the front-end to a backend matrix representation but that shouldn't be too hard.

Malorn44
13th March 2019, 14:56
I ran into an issue where, when scrolling with a trackpad on an overflowed table, it registers item enters I believe. How do I avoid this? Is there a better way to implement this "drawing" feature? Or can I have drawing do nothing while scrolling?

Edit: let me know if you think of a better way of handling this. But I decided to just keep track of if the mouse was pressed using the MouseButtonPress event. This seems to have fixed my issue.

d_stranz
13th March 2019, 16:14
Probably what is happening is that when you are scrolling, your finger slips off the scrollbar "thumb" and onto the table, so it registers that as an itemEntered event, even though the scrollbar still has the input focus because the button is still pressed. Same thing that happens when you press the mouse on a button and then move off it while the button is still pressed. The button highlight will change, but if you move back onto the button to release the mouse, it will cause a click event.

Keeping track of the state of the mouse buttons is probably the best way to handle your situation.