Changing QGraphicsItem stack order with stackBefore - c++

I have a QGraphicsItem "p" with 4 children a, b, c and d, inserted in that order.
#include <QtWidgets/QApplication>
#include <QtWidgets/QGraphicsScene>
#include <QtWidgets/QGraphicsItem>
#include <QtWidgets/QGraphicsView>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QGraphicsScene scene(0, 0, 200, 200);
QGraphicsView view(&scene);
QGraphicsItem* p = new QGraphicsRectItem(nullptr);
scene.addItem(p);
QGraphicsRectItem* a = new QGraphicsRectItem( 0, 0, 40, 40, p);
QGraphicsRectItem* b = new QGraphicsRectItem(10, 10, 40, 40, p);
QGraphicsRectItem* c = new QGraphicsRectItem(20, 20, 40, 40, p);
QGraphicsRectItem* d = new QGraphicsRectItem(30, 30, 40, 40, p);
// cosmetic
p->moveBy(40, 40);
a->setBrush(Qt::blue);
b->setBrush(Qt::red);
c->setBrush(Qt::yellow);
d->setBrush(Qt::green);
view.show();
return app.exec();
}
I want to put item a between c and d like this:
So basically I use stackBefore and do:
a->stackBefore(d);
But it doesn't work. So I took a look at QGraphicsItem's code and it seems like if the item is already stacked before (immediately or not) it will not move:
// Only move items with the same Z value, and that need moving.
int siblingIndex = sibling->d_ptr->siblingIndex;
int myIndex = d_ptr->siblingIndex;
if (myIndex >= siblingIndex) {
I can either do:
b->stackBefore(a);
c->stackBefore(a);
which move all elements under a.
or:
a->setParentItem(nullptr);
a->setParentItem(p);
a->stackBefore(d);
which remove a, and re-insert it on top so I can use stackBefore.
Both solutions look no very efficient. The first one, does not scale and the second one lack semantics.
Is there an elegant way to achieve this ?

I would assign an explicit Z value for each graphics item:
int z = 0;
a->setBrush(Qt::blue);
a->setZValue(++z);
b->setBrush(Qt::red);
b->setZValue(++z);
c->setBrush(Qt::yellow);
c->setZValue(++z);
d->setBrush(Qt::green);
d->setZValue(++z);
And then, before using stackBefore(), change the Z value of the moving item:
a->setZValue(d->zValue());
a->stackBefore(d);

Related

QTableWidget: Prioritize horizontal space for a specific column

I have a QTableWidget that has a column (#3) that needs more space than others. I want to resize all columns to their contents, and give priority to column #3. If column #3 pushes the table's width past what's available, I want column #3 to be truncated with '...' without a horizontal scrollBar.
The screenshot below is the simplest example of the behavior I'm chasing, but I've had to manually adjust the column widths. I want the table to do this automatically.
The following code shows examples of what I've tried on QTableWidget, but none have worked. I've provided inline comments on why the following methods do not work:
table->horizontalHeader()->setStretchLastSection(true);
table->resizeColumnsToContents();
Thank you to anyone who volunteers your time to help me with this.
#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QRect>
#include <QLayout>
#include <QDialog>
#include <QHeaderView>
#include <iostream>
int main( int argc, char* argv[] )
{
QApplication a(argc, argv);
QDialog* d = new QDialog();
d->setLayout( new QVBoxLayout() );
QTableWidget* table = new QTableWidget(1,4);
QStringList headers = {"1", "2", "3", "4"};
table->setHorizontalHeaderLabels(headers);
table->setItem(0, 0, new QTableWidgetItem("1"));
table->setItem(0, 1, new QTableWidgetItem("22222"));
table->setItem(0, 2, new QTableWidgetItem("33333333333333333333333333333"));
table->setItem(0, 3, new QTableWidgetItem("4"));
// Do nothing
//
// The table exceeds the dimensions of the dialog,
// and we get a horizontal scrollbar
// This also results in a horizontal scrollbar
//
// table->horizontalHeader()->setStretchLastSection(true);
// Resizing the columns introduces a horizontal scrollbar, and
// prevents the user from from changing column width
//
// table->resizeColumnsToContents();
// The table fits, but all columns are equally spaced.
// (We want column 3 to take up as much space as possible)
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// Columns are resized to their contents,
// but column 3 is not truncated and we get a horizontal scrollBar
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
d->layout()->addWidget( table );
d->show();
return a.exec();
}
This should work, try it out
#include <QApplication>
#include <QTableWidget>
#include <QStringList>
#include <QRect>
#include <QLayout>
#include <QDialog>
#include <QHeaderView>
#include <QScrollBar>
#include <iostream>
int main( int argc, char* argv[] )
{
QApplication a(argc, argv);
QDialog* d = new QDialog();
d->setLayout( new QVBoxLayout() );
QTableWidget* table = new QTableWidget(1,4);
QStringList headers = {"1", "2", "3", "4"};
table->setHorizontalHeaderLabels(headers);
table->setItem(0, 0, new QTableWidgetItem("1"));
table->setItem(0, 1, new QTableWidgetItem("22222"));
table->setItem(0, 2, new QTableWidgetItem("33333333333333333333333333333"));
table->setItem(0, 3, new QTableWidgetItem("4"));
// Do nothing
//
// The table exceeds the dimensions of the dialog,
// and we get a horizontal scrollbar
// This also results in a horizontal scrollbar
//
// table->horizontalHeader()->setStretchLastSection(true);
// Resizing the columns introduces a horizontal scrollbar, and
// prevents the user from changing column width
//
//resize table
d->layout()->addWidget( table );
d->show();
table->resizeColumnsToContents();
int tableWidth = table->width();
int columsWidth = 0;
int maxColumnWidth = 0;
int maxColumnIndex = 0;
int w = 0;
for(int n = 0; n < table->columnCount(); n++)
{
w = table->columnWidth(n);
columsWidth += w;
if(w > maxColumnWidth)
{
maxColumnWidth = w;
maxColumnIndex = n;
}
}
if(columsWidth > tableWidth)
{
int delta = columsWidth - tableWidth + table->horizontalScrollBar()->height();
maxColumnWidth -= delta;
if(maxColumnWidth < 0)
maxColumnWidth = 0;
table->setColumnWidth(maxColumnIndex, maxColumnWidth);
}
// This table fits, but all the columns are equally spaced.
// (We want column 3 to take up as much space as possible)
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// Columns are resized to their contents,
// but column 3 is not truncated and we get a horizontal scrollBar
//
// table->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
return a.exec();
}
Get back to me if you have any problems with this code.

Problem Changing Regular Value Axis to Log Axis

I have a QT chart with regular value axes. When I toggle a checkbox, I want to change the X Axis from a QValueAxis to a QLogValueAxis. The problem is, when I do this, my data no longer plots to the correct point.
I've tried two approaches (and a bunch of variations on them) to get the log scale to work, but no what I've tried it seems like the data scales itself to fit in the window linearly and ignores the log axis completely.
Approach 1 - Replace the old axis:
QLogValueAxis* xLogAxis = new QLogValueAxis();
xLogAxis->setBase(10);
xLogAxis->setMinorTickCount(10);
dataSeries->attachedAxes()[0] = xLogAxis; //Replace the old X Axis on the series
chart->setAxisX(xLogAxis);
Approach 2 - Make a completely new Chart:
chart->removeSeries(data); //release the data so you don't destroy it
QChart* newChart = new QChart();
ui->graphView->setChart(newChart); //Swap the old chart out then delete it
delete chart;
chart = newChart;
//get rid of the old axes on the data
for(QAbstractAxis* axis : data->attachedAxes()){
data->detachAxis(axis);
}
QValueAxis* yAxis = new QValueAxis();
data->attachAxis(xLogAxis);
data->attachAxis(yAxis);
chart->addAxis(xLogAxis, Qt::AlignBottom);
chart->addAxis(yAxis, Qt::AlignLeft);
chart->addSeries(data);
chart->legend()->setVisible(false);
Any ideas on how to hotswap to a log axis at runtime? Thanks in advance!
In the following example how to exchange axis types:
#include <QtWidgets>
#include <QtCharts>
QT_CHARTS_USE_NAMESPACE
typedef std::function<qreal (const qreal &)> function;
static std::vector<std::pair<function, std::string>> functions{
{[](const qreal & v){ return v;}, "linear"},
{[](const qreal & v){ return v*v; }, "quadratic"},
{[](const qreal & v){ return std::exp(0.01*v);}, "exponential"},
{[](const qreal & v){ return std::sqrt(1 + std::abs(v));}, "square root"}
};
class Widget: public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent=nullptr):
QWidget(parent),
xLogAxis(new QLogValueAxis),
xLinAxis(new QValueAxis),
yAxis(new QValueAxis)
{
xLogAxis->setBase(10);
xLogAxis->setMinorTickCount(10);
view.setChart(&chart);
checkbox.setText("Log Axis");
connect(&checkbox, &QCheckBox::stateChanged, this, &Widget::onStateChanged);
QVBoxLayout *lay = new QVBoxLayout(this);
lay->addWidget(&checkbox);
lay->addWidget(&view);
chart.addAxis(yAxis, Qt::AlignLeft);
// chart.legend()->hide();
// create series
for(const std::pair<function, std::string> & func: functions){
QLineSeries *serie = new QLineSeries;
serie->setName(QString::fromStdString(func.second));
for(int i=0; i< 1000; ++i){
*serie << QPointF(i+1, func.first(i));
}
chart.addSeries(serie);
serie->attachAxis(yAxis);
}
onStateChanged(checkbox.checkState());
}
private slots:
void onStateChanged(int state){
QAbstractAxis *removeaxis, *insertaxis;
if(state == Qt::Checked){
removeaxis = xLinAxis;
insertaxis = xLogAxis;;
}
else{
removeaxis = xLogAxis;
insertaxis = xLinAxis;
}
if(chart.axes(Qt::Horizontal).contains(removeaxis))
chart.removeAxis(removeaxis);
chart.addAxis(insertaxis, Qt::AlignBottom);
for(auto serie: chart.series()){
if(serie->attachedAxes().contains(removeaxis))
serie->detachAxis(removeaxis);
serie->attachAxis(insertaxis);
}
}
private:
QCheckBox checkbox;
QChartView view;
QChart chart;
QLogValueAxis *xLogAxis;
QValueAxis *xLinAxis;
QValueAxis *yAxis;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.resize(640, 480);
w.show();
return a.exec();
}
#include "main.moc"

Qt, QTransform rotation

I'm trying to draw text "on cylinder". It means, that I have five rows of text. Top row is rotated by the X axis for 10 degrees. The second for 5 degrees. The middle is not rotated at all. The four's row is rotated for -5 degrees. The five's is rotated for -10 degrees.
Rows 1, 2, 3 draws OK, but something is wrong with 4,5 rows. What am I doing wrong ?
I provides an image for understanding a problem and code snippet:
for( int i = 0; i < iterationsCount; ++i )
{
const QRect r( x2, y2, textWidth, itemHeight );
const QString text = sections.at( section ).values.at( index );
int rsc = 0;
p->save();
rsc = widgetHeight / 2 - y;
p->setTransform(QTransform().rotate(rsc, Qt::XAxis));
if( type == Section::DaySectionShort ||
type == Section::DaySectionLong )
{
QStringList values = text.split( QLatin1Char( ' ' ) );
p->setPen(
lighterColor( opt.palette.color( QPalette::WindowText ), 75 ) );
p->drawText( r, Qt::AlignLeft | Qt::TextSingleLine, values.at( 0 ) );
p->setPen( opt.palette.color( QPalette::WindowText ) );
p->drawText( r, Qt::AlignLeft | Qt::TextSingleLine, values.at( 1 ) );
}
else
{
p->drawText( r, Qt::AlignLeft | Qt::TextSingleLine, text );
}
p->setTransform(QTransform().rotate(-rsc, Qt::XAxis));
index = nextIndex( index, sections.at( section ).values.size() );
y += itemHeight + itemTopMargin;
p->restore();
}
My problem
As you have not provided a minimal complete code that reproduces the problem, I cannot guess what is wrong there. But the most probable reason is incorrect rsc calculation. At least the following draft works:
#include <QtCore>
#include <QtGui>
#include <QtWidgets>
class MyWidget: public QWidget
{
public:
MyWidget(QWidget *parent = nullptr)
: QWidget(parent)
{
QFont f = font();
f.setPointSize(15);
setFont(f);
}
protected:
void paintEvent(QPaintEvent *event) override
{
QWidget::paintEvent(event);
QPainter p(this);
const int itemHeight = fontMetrics().height();
const int itemTopMargin = 15;
const int xOffset = 15;
int y = itemHeight;
for (size_t i = 0; i < 5; ++i) {
// The angle is in range [-40, 40]. Remove " * 4" for [-10, 10].
const int rsc = (10 - 5 * i) * 4;
qDebug() << i << ":\t" << rsc << "\t" << y;
/*
Rotation must be performed relative to central point of the
drawn item. Transformations below are applied in reverse order.
At first translate item to make it's center in (0, 0). At
second rotate it relative to X axis. At third move the item to
desired position.
*/
QTransform transform;
transform.translate(xOffset, y + itemHeight / 2);
transform.rotate(rsc, Qt::XAxis);
transform.translate(0, - itemHeight / 2);
p.setTransform(transform);
p.drawText(QPoint(), QString("(Item no. %1)").arg(i + 1));
y += itemHeight + itemTopMargin;
}
}
};
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyWidget widget;
widget.setMaximumSize(200, 250);
widget.show();
return app.exec();
}
The transformation used here is complicated because of need to rotate each item relative to it's central y, not y = 0. This also may be the case.
Font and angles are increased to see considered effects better.

Bad pointer error in class when passing array

So I'm writing a simple battlesystem for a game and I'm getting an error passing an array of pointers to the battlesystem class.
//Create the player and 3 enemies
Battler player("Player", 100, 100, 50, 50, 50, 50, 90);
Battler foe1("Imp", 100, 100, 50, 50, 50, 50, 80);
Battler foe2("Ogre", 100, 100, 50, 50, 50, 50, 75);
Battler foe3("Giant", 100, 100, 50, 50, 50, 50, 60);
//Create an array of pointers that point to the enemies
Battler *foes[3];
foes[0] = &foe1;
foes[1] = &foe2;
foes[2] = &foe3;
//Initialize the battlesystem passing the player, the array of enemies
//and the number of enemies (3)
BattleSystem *btl = new BattleSystem(&player, *foes, 3);
So this was working fine, but when I pass the array to the class, the first member is passed fine, but the rest are passed and when I do a breakpoint, they are sent as "Badptr".
Here is the code for the battlesystem constructor:
BattleSystem::BattleSystem(Battler *plyr, Battler enemies[], int numEnemies)
{
player = plyr;
//foe is declared as Battler *foe; So it just points to the first member of the enemies
// array so I can access them. But only the first member gets a value the rest get
// "Bad ptr" with garbage values and when I look through the enemies array passed
// to the constructor, it has BAD PTRs in everything but the first element.
foe = enemies;
numFoes = numEnemies;
totalTurns = 0;
foeTurns = new int[numFoes];
turnList = new Battler*[numFoes + 1];
for(int i = 0; i <= numFoes; i++)
{
turnList[i] = &foe[i];
}
turnList[numFoes + 1] = player1;
}
I'm missing something obvious I think, but can anyone share some wisdom?
Thank you.
Leaving aside style issues about naked pointers and ownership, I believe you mean
// v-- array of pointers
BattleSystem::BattleSystem(Battler *plyr, Battler *enemies[], int numEnemies)
And
BattleSystem *btl = new BattleSystem(&player, foes, 3);

Correctly implementing a custom QWidget in Qt

I'm completely new to Qt/GUI programming and I'm trying to create the UI for a simple Tic Tac Toe game. I created two custom QWidget classes. My main window class (GameWindow) extends the base QWidget, and my other class XOSpace extends QFrame. XOSpace serves two purposes: dividing up the board into spaces (each one will have a HLine or VLine shape), and being a starting point for drawing X's and O's in the correct spot on the board (as soon as I can figure out how to use Qt painters and paint events). My problem is that when I add the XOSpaces to GameWindow they don't display. But when I added QFrame objects from the base class as a test, they displayed fine. How do I extend QFrame (or any widget class), and still make sure it will function the same as the base classes in Qt? Are there any functions I need to reimplement? Anything else?
class XOSpace : public QFrame {
Q_OBJECT
private:
XO xo ; //enum representing whether this space holds an X, O, or blank
public:
explicit XOSpace(QWidget *parent = 0) ;
explicit XOSpace(QWidget *parent, int size, QFrame::Shape) ;
~XOSpace();
void setXO(XO) ;
};
XOSpace::XOSpace(QWidget *parent) : QFrame(parent) {
this->xo = XO::blank ;
this->setGeometry(QRect());
this->setFrameShape(QFrame::HLine) ;
this->setFrameShadow(QFrame::Sunken) ;
this->setMinimumWidth(96) ;
this->setLineWidth(1) ;
this->show();
}
XOSpace::XOSpace(QWidget* parent, int size, QFrame::Shape shape) : QFrame(parent) {
this->xo = XO::blank ;
this->setGeometry(QRect());
this->setFrameShape(shape);
this->setFrameShadow(QFrame::Sunken);
this->setMinimumWidth(size) ;
this->setLineWidth(1) ;
this->show() ;
}
QSize XOSpace::sizeHint() const {
return this->size();
}
void XOSpace::setXO(XO xo) {
this->xo = xo ;
}
XOSpace::~XOSpace() {
;
}
namespace Ui {
class GameWindow;
}
class GameWindow : public QWidget {
Q_OBJECT
private:
Ui::GameWindow *ui ;
//these don't display:
vector<XOSpace*>* hSpaces ;
//these do:
QFrame* vLineOne ;
/* declare 7 more
like this */
public:
explicit GameWindow(QWidget *parent = 0);
~GameWindow();
friend class XOSpace ;
};
GameWindow::GameWindow(QWidget *parent) : QWidget(parent),
ui(new Ui::GameWindow) {
ui->setupUi(this);
this->setWindowTitle("Hello world!");
QGridLayout *mainLayout = new QGridLayout() ;
mainLayout->setColumnMinimumWidth(0, 25);
mainLayout->setColumnMinimumWidth(6, 25);
this->setLayout(mainLayout) ;
QPushButton* button = new QPushButton("Play") ;
button->setFixedWidth(100);
mainLayout->addWidget(button, 2, 3) ;
QGridLayout* secondaryLayout = new QGridLayout() ;
mainLayout->addLayout(secondaryLayout, 1, 1, 1, 5);
QGroupBox* gBox = new QGroupBox() ;
secondaryLayout->addWidget(gBox, 0, 0);
QGridLayout* boardLayout = new QGridLayout() ;
gBox->setLayout(boardLayout);
hSpaces = new vector<XOSpace*>() ;
vLineOne = new QFrame() ;
vLineOne->setGeometry(QRect());
vLineOne->setFrameShape(QFrame::VLine);
vLineOne->setFrameShadow(QFrame::Sunken);
vLineOne->setMinimumHeight(96) ;
/*repeat for vLines 2-4
*/
vLineFive = new QFrame() ;
vLineFive->setGeometry(QRect());
vLineFive->setFrameShape(QFrame::VLine);
vLineFive->setFrameShadow(QFrame::Sunken);
vLineFive->setMinimumHeight(48);
/*repeat for vLines 6-8
*/
for(vector<XOSpace*>::size_type i = 0 ; i < 6 ; i++) {
hSpaces->push_back(new XOSpace(this, 96,
QFrame::HLine));
}
//horizontal spaces: (don’t display properly)
boardLayout->addWidget(hSpaces->at(0), 0, 0,
Qt::AlignBottom);
boardLayout->addWidget(hSpaces->at(1), 0, 2,
Qt::AlignBottom);
boardLayout->addWidget(hSpaces->at(2), 0, 4,
Qt::AlignBottom);
boardLayout->addWidget(hSpaces->at(3), 3, 0, Qt::AlignTop);
boardLayout->addWidget(hSpaces->at(4), 3, 2, Qt::AlignTop);
boardLayout->addWidget(hSpaces->at(5), 3, 4, Qt::AlignTop);
//vertical spaces: (display OK)
boardLayout->addWidget(vLineOne, 0, 1) ;
boardLayout->addWidget(vLineFive, 1, 1) ;
boardLayout->addWidget(vLineTwo, 0, 3) ;
boardLayout->addWidget(vLineSix, 1, 3) ;
boardLayout->addWidget(vLineThree, 2, 1) ;
boardLayout->addWidget(vLineSeven, 3, 1) ;
boardLayout->addWidget(vLineFour, 2, 3) ;
boardLayout->addWidget(vLineEight, 3, 3) ;
mainLayout->setRowStretch(0, 1);
//set rows and columns stretch
mainLayout->setVerticalSpacing(0) ;
//set spacing etc.
}
GameWindow::~GameWindow() {
delete ui;
if (hSpaces != nullptr) {
for(vector<XOSpace*>::size_type i = 0 ; i < hSpaces->size() ; i++) {
if (hSpaces->at(i) != nullptr) {
delete hSpaces->at(i) ;
}
}
delete hSpaces ;
}
}
The XOSpaces are supposed to be drawn as horizontal line segments that will make up the two horizontal lines on a tic tac toe board. Here's what my application looks like now:
Here is a lot of little pieces of advice. The first GUI or two that you make in Qt will probably be pretty hard to do. Using layouts, like you have started doing will help quite a bit.
So here are the first couple recommendations I would give:
Don't call show in your xospace constructors. Adding them to a layout, makes it the parent's job to show it. So in your main when you call gameWindow->show(); it handles all the showing of nested elements.
QLabel is a subclass of QFrame. Change the elements in question to be of type QLabel and then add in setText("X") to their constructor or somewhere to make sure you can see your elements.
If you aren't using a the UI form, I would leave it out.
Based on your game layout, this is what your variables look like:
// vL1 vL2
// hs0 vL6 hs1 vL5 hs2
// vL3 vL4
// hs3 vL7 hs4 vL8 hs5
// ??? ???
Instead of relying on the size of these vertical and horizontal lines for your stretching and size constraints, why not use the elements that will sit on the board, like in spots marked with an X below:
// X vL1 X vL2 X
// hs0 vL6 hs1 vL5 hs2
// X vL3 X vL4 X
// hs3 vL7 hs4 vL8 hs5
// X ??? X ??? X
This would allow you to take two and span them across the grid.
boardLayout->addWidget(vLines.at(0), 0, 1, 5, 1) ;
boardLayout->addWidget(vLines.at(1), 0, 3, 5, 1) ;
mainLayout->setRowStretch(1, 1);
Then like I hint above, you could use a QList or a QVector to remove so much copy and paste code.
vLines.append(new QFrame);
vLines.append(new QFrame);
foreach(QFrame * f, vLines)
{
//f->setGeometry(QRect());
f->setFrameShape(QFrame::VLine);
f->setFrameShadow(QFrame::Sunken);
f->setMinimumHeight(96);
}
Also setGeometry() is useful if you aren't using layouts. And setting the geometry to QRect(), is probably equivalent to the default constructor it has.
And when you start putting object trees together, you don't have to worry as much about how they clean up:
http://qt-project.org/doc/qt-4.8/objecttrees.html
EDIT:
Here is how I would layout the board:
QGridLayout * board = new QGridLayout();
for(int r = 0; r < 5; r++)
{
for(int c = 0; c < 5; c++)
{
if(r % 2 == 1)
{
if(c % 2 == 1)
{
// is an intersection
// leave it blank?
// or add a box?
}
else
{
// is a horizontal line
QFrame * f = new QFrame();
f->setFrameShape(QFrame::HLine);
f->setFrameShadow(QFrame::Sunken);
f->setMinimumWidth(96);
board->addWidget(f,r, c);
}
}
else
{
if(c % 2 == 1)
{
// is a vertical line
QFrame * f = new QFrame();
f->setFrameShape(QFrame::VLine);
f->setFrameShadow(QFrame::Sunken);
f->setMinimumHeight(96);
board->addWidget(f, r, c);
}
else
{
// is an XO location
board->addWidget(new QLabel(), r, c, Qt::AlignCenter);
}
}
}
}
setLayout(board);
Then if you just let QGridLayout manage your item's location and access, you do something like this:
void GameWindow::setXO(QString val, int r, int c)
{
// upper left xo location is 0,0
// lower right xo location is 2,2
// we map to skip the frame locations
if(r > 2 || r < 0 || c < 0 || c > 2)
{
qDebug() << "Error in setXO" << r << c;
return;
}
QLabel * xo = qobject_cast<QLabel*>(board->itemAtPosition(r*2, c*2)->widget());
if(xo != 0)
{
xo->setText(val);
}
}
Hope that helps.