Qt5 QPushButton's can't be clicked (?!) - c++

I have an inherited widget game_widget in which I declared 9 QPushButton's that are stored in an array via a method init_ui and a layout widget on which the buttons are supposed to be placed. There is also init_ui function that is called in the constructor. Here are the main elements of the class:
class game_widget : public QWidget
{
Q_OBJECT
public:
// The layout widget for the buttons
QWidget* gridLayoutWidget = new QWidget(this);
QPushButton** fields; // Fields list
QPushButton* field1 = new QPushButton(gridLayoutWidget);
...
QPushButton* field9 = new QPushButton(gridLayoutWidget);
...
private:
void init_ui();
};
Here is init_ui:
void game_widget::init_ui()
{
fields = new QPushButton* [9]; // Fields list
fields[0] = field1;
...
fields[8] = field9;
...
// Preparing layout for the buttons
gridLayoutWidget->setGeometry(QRect(10, 10, 531, 531));
QGridLayout* grid_layout = new QGridLayout(gridLayoutWidget);
// Adding each field to the layout
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
fields[i * 3 + j]->setMaximumSize(QSize(170, 170));
fields[i * 3 + j]->setMinimumSize(QSize(170, 170));
grid_layout->addWidget(fields[i * 3 + j], i, j);
}
}
Now the thing is that those buttons are not even clickable - not to mention that hovering over them doesn't do anything with them as well, there is no animation. Nothing else about them was changed, so their behavior should be normal, but it isn't. If You have the slightest idea what might be going on, please help.

You are creating 9 extra QPushButtons in void game_widget::init_ui(), try the following:
void game_widget::init_ui()
{
QVector <QPushButton*> fields; // Fields list
fields[0] << field1;
...
fields[8] << field9;
...
// Preparing layout for the buttons
gridLayoutWidget->setGeometry(QRect(10, 10, 531, 531));
QGridLayout* grid_layout = new QGridLayout(gridLayoutWidget);
// Adding each field to the layout
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
fields[i * 3 + j]->setMaximumSize(QSize(170, 170));
fields[i * 3 + j]->setMinimumSize(QSize(170, 170));
grid_layout->addWidget(fields[i * 3 + j], i, j);
}
}

Related

QGroupBox's child restricts shrink the form

I have a multiple screen video player, and I just want to keep 16:9 ratio. There is a qgroupbox as a container of a qwidget which plays video in it. I also use qgroupbox to show selected frame by painting border to green. I can't do this on qwidget because rendered video overlaps that. When I have done with resize, I emit a signal with mouseup event to be able to informed about the resize operation completed. Then I calculate new bounds for qwidget to keep 16:9 ratio and apply this values for qwidget. Here is the image to show you how my app looks like:
And here is the code that I use to resize qwidgets:
void playBack::OnWindowResized()
{
float ratio = 16.0f / 9.0f;
float w = playBackplayer_contList.at(0)->size().width(); //qgroupbox's width
float h = playBackplayer_contList.at(0)->size().height();//qgroupbox's height
float currentRatio = w / h;
float newW = 0;
float newH = 0;
if (currentRatio > ratio)
{
newH = h;
newW = h*ratio;
}
else if (currentRatio < ratio)
{
newW = w;
newH = w / ratio;
}
qDebug() << "NEW WIDGET SIZE: " << (int)newW << " x " << (int)newH;
for (int i = 0; i < playBackplayer_widgtList.count(); i++)
{
playBackplayer_widgtList.at(i)->setMinimumSize(newW, newH);
//playBackplayer_widgtList.at(i)->resize(newW, newH);
}
}
This code works perfectly when I enlarge form, but When I want to shrink, It doesn't allow me to do that. Because I set a minimum value for qwidgets. If I don't use setMinimumSize, use resize(w,h) instead, than orientation problems occur. And here is a example for this issue:
This code below shows ctor and this is where I set the layout:
playBack::playBack()
{
playback_player_1_widget = new QWidget;
playback_player_2_widget = new QWidget;
playback_player_3_widget = new QWidget;
playback_player_4_widget = new QWidget;
playback_player_1_widget_cont = new QGroupBox;
playback_player_2_widget_cont = new QGroupBox;
playback_player_3_widget_cont = new QGroupBox;
playback_player_4_widget_cont = new QGroupBox;
playBackplayer_widgtList.append(playback_player_1_widget);
playBackplayer_widgtList.append(playback_player_2_widget);
playBackplayer_widgtList.append(playback_player_3_widget);
playBackplayer_widgtList.append(playback_player_4_widget);
playBackplayer_contList.append(playback_player_1_widget_cont);
playBackplayer_contList.append(playback_player_2_widget_cont);
playBackplayer_contList.append(playback_player_3_widget_cont);
playBackplayer_contList.append(playback_player_4_widget_cont);
int rowcnt = 0;
int colcnt = 0;
for (int i = 0; i < 4; i++)
{
playBackplayer_contList.at(i)->setStyleSheet(QString("border:1px solid #000;background-color:#000;"));
playBackplayer_widgtList.at(i)->setStyleSheet(QString("background-color:#f00;"));
QGridLayout* layout = new QGridLayout;
layout->setRowStretch(0, 1);
layout->setColumnStretch(0, 1);
layout->setRowStretch(2, 1);
layout->setColumnStretch(2, 1);
playBackplayer_widgtList.at(i)->setMinimumWidth(100);
playBackplayer_widgtList.at(i)->setMinimumHeight(100);
playBackplayer_widgtList.at(i)->setMaximumWidth(10000);
playBackplayer_widgtList.at(i)->setMaximumHeight(10000);
layout->addWidget(playBackplayer_widgtList.at(i),1,1);
layout->setMargin(0);
layout->setSpacing(0);
playBackplayer_contList.at(i)->setLayout(layout);
mainLayout->addWidget(playBackplayer_contList.at(i), colcnt, rowcnt);
rowcnt++;
if (rowcnt % 2 == 0)
{
rowcnt = 0;
colcnt++;
}
playBackplayer_widgtList.at(i)->setAcceptDrops(true);
}
}
I have tried various things, I have tried to set size 0 for qwidget before resize, (in mousedownevent) that didn't work, I have tried deleting layout for qgroupbox, after resize happens, create new layout and set it for groupbox, that didn't work, I have tried layout()->adjustSize(), update(), repaint(), all that stuff didn't work. What am I missing? I need helps from you. Any help would be appreciated. Thank you in advance.
Do away with the grid layout inside the container group boxes. Instead, align and resize the video widget with setGeometry
Here is a simple subclass of QGroupBox I made that keeps your desired ratio and always stays in the center:
class RatioGroupBox : public QGroupBox{
Q_OBJECT
public:
RatioGroupBox(QWidget *parent = nullptr) : QGroupBox (parent){
setFlat(true);
setStyleSheet("border:1px solid #000;background-color:#000;");
setMinimumSize(100, 100);
setMaximumSize(10000, 10000);
ratio = 16.0f/9.0f;
ratioWidget = new QWidget(this);
ratioWidget->setStyleSheet("background: #f00;");
ratioWidget->setAcceptDrops(true);
}
protected:
void resizeEvent(QResizeEvent *){//or you can use your own resize slot
float w = width();
float h = height();
float currentRatio = w/h;
float newW(0);
float newH(0);
if (currentRatio > ratio){
newH = h;
newW = h*ratio;
}
else if (currentRatio < ratio){
newW = w;
newH = w / ratio;
}
ratioWidget->setGeometry((w-newW)/2, (h-newH)/2, newW, newH);
}
private:
QWidget *ratioWidget;
float ratio;
};
Your entire ctor will become something like:
playBack::playBack()
{
for(int r=0; r<2; r++){
for(int c=0; c<2; c++){
RatioGroupBox* playback_player_cont = new RatioGroupBox;
mainLayout->addWidget(playback_player_cont, c, r);
playBackplayer_contList.append(playback_player_cont);
}
}
}
You can of course access your video widgets by exposing ratioWidget any way you like. Either by making it public or creating a getter function.

Fetch text from unnamed QGraphicsTextItem

A friend of mine and I are currently trying to make a game in C++ using Qt. Our current problem is that we need to fetch text from a QGraphicsTextItem on a button mousePressEvent. In the game menu it is possible to choose how many players there are, therefore we've placed a QGraphicsTextItem in a for-loop to make it possible for all the users to type in their names. Because of the for-loop, we don't have names for every single text item object so we can store the names. We've managed to store all the memory addresses to the objects using QMap, but we don't know how to get the text of of this. We don't even know if this is the best way to do it.
GameInfo.h
class GameInfo {
public:
GameInfo();
int players;
QStringList names = (QStringList() // Default player names. This array should be overwritten by the custom names
<< "Player 1"
<< "Player 2"
<< "Player 3"
<< "Player 4"
<< "Player 5"
<< "Player 6"
<< "Player 7");
QMap<int, QGraphicsTextItem**> textBoxMap; // This is where we store all the addresses
};
Game.cpp
QGraphicsRectItem * overviewBox = new QGraphicsRectItem();
overviewBox->setRect(0, 0, 782, 686);
scene->addItem(overviewBox);
int faceNo = 0;
// Create the player selection section
for(int i = 1; i <= players; i++) { // "players" is defined another place in the code, and is an integer between 1 and 6
Container * selContainer = new Container();
selContainer->Selection(i, faceNo);
selContainer->setPos(50, 70 + 110 * (i - 1));
scene->addItem(selContainer);
Container * ovContainer = new Container(overviewBox);
ovContainer->Overview(i, faceNo);
ovContainer->setPos(0, 0 + 110 * (i - 1));
info->textBoxMap.insert(i, &selContainer->textBox->playerText); // This is where we save the addresses
}
Selection.cpp
extern Game * game;
Container::Container(QGraphicsItem * parent): QGraphicsRectItem(parent) {
}
void Container::Selection(int nPlayers, int sPiceNo, QGraphicsItem *parent) {
QString numName = QString::number(nPlayers);
setRect(0, 0, 672, 110);
this->setPen(Qt::NoPen); // Removes border
int posY = this->rect().height() / 2;
QSignalMapper * signalMapper = new QSignalMapper(this);
arrowL = new Arrow(0, posY - 32, 0, this);
piece = new Piece(sPiceNo, 96, posY - 32, 1, 1, this);
arrowR = new Arrow(192, posY - 32, 1, this);
textBox = new TextBox(game->info->names[nPlayers - 1], true, this);
textBox->setPos(288, posY - 32);
lockBtn = new Button("Lock", 96, 32, this);
connect(lockBtn, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(lockBtn, nPlayers);
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(lock(int)));
lockBtn->setPos(640, posY - 16);
}
void Container::Overview(int ovPlayers, int ovPiceNo, QGraphicsItem * parent) {
// Some code...
}
void Container::lock(int nPlayer) {
qDebug() << game->info->textBoxMap[nPlayer];
qDebug() << game->info->names[nPlayer - 1];
game->info->names[nPlayer - 1] = **game->info->textBoxMap[nPlayer].toPlainText(); // This line causes an error
}
The error that occurs because of the last line looks like this:
error: no match for 'operator=' (operand types are 'QString' and 'QGraphicsTextItem')
game->info->names[nPlayer - 1] = **game->info->textBoxMap[nPlayer];
^
TextBox.cpp
TextBox::TextBox(QString text, bool editable, QGraphicsItem * parent): QGraphicsRectItem(parent) {
this->editable = editable;
// Draw the textbox
setRect(0, 0, 320, 64);
if(!editable) {
this->setPen(Qt::NoPen); // Removes border
}
else if(editable) {
QBrush brush;
brush.setStyle(Qt::SolidPattern);
brush.setColor(QColor(255, 255, 255, 255));
setBrush(brush);
}
// Draw the text
playerText = new QGraphicsTextItem(text, this);
int fontId = QFontDatabase::addApplicationFont(":/fonts/built_titling_bd.ttf");
QString family = QFontDatabase::applicationFontFamilies(fontId).at(0);
QFont built(family, 25);
playerText->setFont(built);
int xPos = 0;
int yPos = rect().height() / 2 - playerText->boundingRect().height() / 2;
playerText->setPos(xPos,yPos);
}
My question is how do i fetch the text from the QGraphicsTextItem?
You should try to learn a bit more about C++ before trying to develop a game imo. (Having public variables is against OO's and C++ paradigm)
But here is what you are looking for:
http://doc.qt.io/qt-5/qgraphicstextitem.html#toPlainText
EDIT:
If you are not able to debug some line of code, I could only recommend to try to seperate your code in order to have a minimum of call in a single line. I haven't try the code bellow, but that how you should try to debug your code:
void Container::lock(int nPlayer)
{
qDebug() << game->info->textBoxMap[nPlayer];
qDebug() << game->info->names[nPlayer - 1];
QGraphicsTextItem **value = game->info->textBoxMap.value(nPlayer, nullptr);
game->info->names[nPlayer - 1] =(*value)->toPlainText();
}

Updating QGridLayouts

Hi guys I'm coding game for my studies and I've big problems with that (My leg was injured and I couldn't go to lessons).
My job is to do simple Battleships game in c++, qt.
I'm in point where logic code is done, but gui is a big mess.
Here's code for gui .cpp file:
#include <QtWidgets>
#include "dialog.h"
Dialog::Dialog()
{
createGraczBox();
createKomputerBox();
createOdpowiedz();
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(graczBox , 0 , 0 );
mainLayout->addWidget(komputerBox , 0 , 1 );
mainLayout->addWidget(Odpowiedz , 0 , 2 );
setLayout(mainLayout);
setFixedSize(800,400);
setWindowTitle(tr("Battleships!"));
}
void Dialog::createGraczBox()
{
graczBox = new QGroupBox(tr("Gracz"));
QGridLayout *layout = new QGridLayout;
for (int j = 0; j < NumGridRows; ++j) {
labels[j] = new QLabel(tr("%0").arg(j+1));
layout->addWidget(labels[j], 0 , j + 1 , Qt::AlignLeft);
}
for (int i = 0; i < NumGridRows; ++i) {
labels[i] = new QLabel(tr("%0").arg(i + 1));
layout->addWidget(labels[i], i + 1, 0);
}
for(int g = 1;g<10;++g)
{
layout->setColumnStretch(g,1);
}
graczBox->setLayout(layout);
}
void Dialog::createKomputerBox()
{
komputerBox = new QGroupBox(tr("Komputer"));
QGridLayout *layout = new QGridLayout;
for (int j = 0; j < NumGridRows; ++j) {
labels[j] = new QLabel(tr("%0").arg(j+1));
layout->addWidget(labels[j], 0 , j + 1 );
}
for (int i = 0; i < NumGridRows; ++i) {
labels[i] = new QLabel(tr("%0").arg(i + 1));
layout->addWidget(labels[i], i + 1, 0);
}
for(int g = 1;g<10;++g)
{
layout->setColumnStretch(g,1);
}
komputerBox->setLayout(layout);
}
void Dialog::createOdpowiedz()
{
Odpowiedz = new QGroupBox(tr("Komendy"));
QFormLayout *layout = new QFormLayout;
xLabel = new QLabel;
QPushButton *zmienna_x_przycisk = new QPushButton(tr("X"));
connect(zmienna_x_przycisk, SIGNAL(clicked()), this, SLOT(setx()));
yLabel = new QLabel;
QPushButton *zmienna_y_przycisk = new QPushButton(tr("Y"));
connect(zmienna_y_przycisk, SIGNAL(clicked()), this, SLOT(sety()));
xLabel->setText(tr("Aktualne X: %1").arg(zmienna_x));
yLabel->setText(tr("Aktualne Y: %1").arg(zmienna_y));
layout->addRow(xLabel);
layout->addRow(zmienna_x_przycisk);
layout->addRow(yLabel);
layout->addRow(zmienna_y_przycisk);
Odpowiedz->setLayout(layout);
}
void Dialog::setx()
{
bool ok_x;
x = QInputDialog::getInt(this, tr("Podaj X:"),
tr(""), 1, 1, 10, 1, &ok_x);
if (ok_x)
x=zmienna_x;
}
void Dialog::sety()
{
bool ok_y;
y = QInputDialog::getInt(this, tr("Podaj Y:"),
tr(""), 1, 1, 10, 1, &ok_y);
if (ok_y)
y=zmienna_y;
}
They way it should work:
I'm choosing x and y by clicking on it.
Choosing numbers in new window.
They should appear in "Aktualne X:/Y:".
When I've x and y, click ok button (he's not there by now).
Computer checking numbers marking it in space Komputer / Gracz.
Reset x and y to 0.
Show text "You missed. Computer missed."
Go on till one'll win.
But I don't know how to make my layout updating itself by other actions. I can't make dowhile work here.
You need to use signals and slots here. Create "OK" button and connect it to a function, that will be used to handle your x and y variables.

QT QTableWidget::item() returns nullptr even when widget assigned to it

This is driving me nuts. Here's the relevant code:
//Inside UI class
QTableWidget *table_view;
Later,
QLabel* lb_param_id = new QLabel(this);
lb_param_id->setText(QString::number(param_id));
QLabel* lb_param_name = new QLabel(this);
lb_param_name->setText(QString(param_name));
QLineEdit* te_value = new QLineEdit(this);
te_value->setText(QString(value));
QPushButton* pb_command = new QPushButton();
pb_command->setText("Change");
...
if(ui->table_view->rowCount() <= param_id)
ui->table_view->setRowCount(param_id + 1);
ui->table_view->setCellWidget(param_id, 0, lb_param_id);
ui->table_view->setCellWidget(param_id, 1, lb_param_name);
ui->table_view->setCellWidget(param_id, 2, te_value);
ui->table_view->setCellWidget(param_id, 3, pb_command);
for(int i =0; i < ui->table_view->rowCount(); ++i)
{
for(int j = 0; j < ui->table_view->columnCount(); ++j)
{
QTableWidgetItem* item = ui->table_view->item(i, j);
//Here, item is nullptr. Why?
item->setForeground(QColor::fromRgb(255,255,255));
}
}
I set widgets, then try to change foreground of all widgets inside QTableWidget. However, what is returned from ui->table_view->item() is nullptr. What is going on here? btw, The column count is set at initialization.
Add following few lines of code.
if(ui->table_view->rowCount() <= param_id)
ui->table_view->setRowCount(param_id + 1);
ui->table_view->setColumnCount(4);
ui->table_view->setItem(param_id, 0, new QTableWidgetItem());
ui->table_view->setItem(param_id, 1, new QTableWidgetItem());
ui->table_view->setItem(param_id, 2, new QTableWidgetItem());
ui->table_view->setItem(param_id, 3, new QTableWidgetItem());
ui->table_view->setCellWidget(param_id, 0, lb_param_id);
...
Basically, you need to insert the data into the cell first before you can set widget. In your case, you don't have meaning fully data.
Inspecting the qt source, this is the how setCellWidget() imaplemented:
void QTableWidget::setCellWidget(int row, int column, QWidget *widget)
{
QModelIndex index = model()->index(row, column, QModelIndex());
QAbstractItemView::setIndexWidget(index, widget);
}
Without setting the cell first, the model index is invalid index. I agree qt should insert the data if returned index is invalid. For now, you have to work with qt code.

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.