PDA

View Full Version : Paint in a QtableView



StrikeByte
18th December 2014, 11:25
I'm trying to paint a alternating color in a QtableView (can't use the default alternating color, or a delegate because the delegate only paints for existing rows and not the entire table)

im painting in the viewport this works fine until scrollbars are needed and start scrolling then the alternating colors do not linup with the rows

how do i compensate for the scrolling?


this is the code for painting in the viewport (this has alignment problems)


void TableView::paintEvent(QPaintEvent *e)
{
int rowH = this->rowHeight(0);
if(rowH == 0)
rowH = 30;

QPainter painter(this->viewport());

int vpH = this->viewport()->height();

int count = vpH/rowH;
QBrush oldBrush = painter.brush();

for(int i = 0; i <= count; i++)
{
//painter.drawLine(0,i*rowH-1,this->viewport()->width(),i*rowH-1);
if(i%2 != 0)
painter.fillRect(0,i*rowH,this->viewport()->width(),rowH,palette().alternateBase()); //odd color
else
painter.fillRect(0,i*rowH,this->viewport()->width(),rowH,palette().background()); //even color
}
painter.setBrush(oldBrush);

QTableView::paintEvent(e);
}


i tried to paint the entire widget and let the scroll area take care of scrolling the widget but im getting the following messages:

QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::brush: Painter not active
QPainter::setBrush: Painter not active

this is the code for painting in the widget (gives me the messages)


void TableView::paintEvent(QPaintEvent *e)
{
int rowH = this->rowHeight(0);
if(rowH == 0)
rowH = 30;

QPainter painter(this);

int vpH = this->height();

int count = vpH/rowH;
QBrush oldBrush = painter.brush();

for(int i = 0; i <= count; i++)
{
//painter.drawLine(0,i*rowH-1,this->viewport()->width(),i*rowH-1);
if(i%2 != 0)
painter.fillRect(0,i*rowH,this->viewport()->width(),rowH,palette().alternateBase()); //odd color
else
painter.fillRect(0,i*rowH,this->viewport()->width(),rowH,palette().background()); //even color
}
painter.setBrush(oldBrush);

QTableView::paintEvent(e);
}

d_stranz
18th December 2014, 19:33
can't use the default alternating color

And why not? Are the colors wrong for your needs? Then change them by changing the palette for your QTableView instance. The painting code in the table widget should be doing something very similar to what you are trying.

StrikeByte
19th December 2014, 08:00
Alternating colors only paints the filled rows and not the entire table, in the treeview there is a option that will paint entire view but that option is not available in the tableview

d_stranz
19th December 2014, 16:37
The easiest way to solve this might be to place a proxy model between your original model and the table view. The proxy will be dedicated to the view, so it can keep track of the number of filled vs. unfilled rows visible on the screen. You'll probably need to give it a pointer to the view so it can ask for geometry information; you might also connect it to scrollbar signals in the table view so it can recompute the number of "virtual rows" (model rows + empty visible rows).

In this proxy, you should re-implement rowCount() to return the count of "virtual rows". You will also need to re-implement the data() method. For each row index < source model row count, you simply call the source model's data() method. For any row index >=source model row count, you need to return an empty QVariant for the DisplayRole (to show an empty cell), and a QBrush with either the QPalette::Base or QPalette::AlternatingBase color for the BackgroundRole depending on whether the virtual row index is odd or even.

If recomputing the the virtual row count is too much hassle, you could simply say that the number of virtual rows is equal to the number of model rows plus one screen full of empty rows, and set the view's scrollbar limits appropriately. That way, unless the view is resized you can always be assured that the user can never scroll below the size of a screen full of empty rows.