Witam, korzystam z książki "Game Programming Using QT". Rozwijam tam podaną w przykładzie grę TicTacToe. Problem jest taki że przy zmianie rozmiaru okna programu ( tym samym planszy i pól w postaci przycisków ) czcionka dla przycisków pozostaje taka sama. Próbowałem rozwiązać to tak:
///-------------------------------------------------------------------------
void TicTacToeWidget::buttonsResizeEvent(){
for(int i=0; i<board.size(); ++i){
QPushButton* button = board.at(i);
int size = button->geometry().height();
QFont font = button->font();
font.setPointSize(size/2);
button->setFont(font);
}
}
///-------------------------------------------------------------------------
TicTacToeWidget::TicTacToeWidget(QWidget *parent)
: QWidget(parent) {
gridLayout = new QGridLayout(this);
connect(this, SIGNAL(QResizeEvent), this, SLOT(buttonsResizeEvent()));
}
Problem jest jednak taki że sygnał nie jest w ogóle rozpoznawany:
QObject::connect: No such signal TicTacToeWidget::QResizeEvent()
Szukałem informacji, początkowo chciałem to zrobić w CSS dla przycisków podając procentowe wymiary czcionki. Nic jednak mi nie działało. Będę wdzięczny za pomoc.
Dla pewności daje cały kod programu:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "tictactoewidget.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void startNewGame();
private slots:
void updateNameLabels();
void handleGameOver(TicTacToeWidget::Player winner);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "configurationdialog.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->actionNewGame, SIGNAL(triggered()),
this, SLOT(startNewGame()));
connect(ui->actionQuit, SIGNAL(triggered()),
qApp, SLOT(quit()));
connect(ui->gameBoard, SIGNAL(currentPlayerChanged(Player)),
this, SLOT(updateNameLabels()));
connect(ui->gameBoard, SIGNAL(gameOver(TicTacToeWidget::Player)),
this, SLOT(handleGameOver(TicTacToeWidget::Player)));
ui->gameBoard->setEnabled(false);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::startNewGame() {
ConfigurationDialog dlg(this);
if(dlg.exec()==QDialog::Rejected) {
return;
}
ui->player1->setText(dlg.player1Name());
ui->player2->setText(dlg.player2Name());
ui->gameBoard->setupBoard(dlg.boardSizeSlider());
ui->gameBoard->initNewGame();
ui->gameBoard->setEnabled(true);
updateNameLabels();
updateNameLabels();
QFont f = ui->player2->font();
f.setBold(true);
ui->player2->setFont(f);
}
void MainWindow::updateNameLabels() {
QFont f = ui->player1->font();
f.setBold(ui->gameBoard->currentPlayer() ==
TicTacToeWidget::Player1);
ui->player1->setFont(f);
f = ui->player2->font();
f.setBold(ui->gameBoard->currentPlayer() ==
TicTacToeWidget::Player2);
ui->player2->setFont(f);
}
void MainWindow::handleGameOver(TicTacToeWidget::Player winner) {
ui->gameBoard->setEnabled(false);
QString message;
if(winner == TicTacToeWidget::Draw) {
message = "Game ended with a draw.";
} else {
message = QString("%1 wins").arg(winner == TicTacToeWidget::Player1
? ui->player1->text() : ui->player2->text());
};
QMessageBox::information(this, "Info", message);
}
tictactoewidget.h
#ifndef TICTACTOEWIDGET_H
#define TICTACTOEWIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QGridLayout>
class QPushButton;
class TicTacToeWidget : public QWidget {
Q_OBJECT
public:
enum Player { // nie może być w sekcji prywatnej!!!
Invalid, Player1, Player2, Draw
};
private:
Q_ENUMS(Player)
Q_PROPERTY(Player currentPlayer READ currentPlayer WRITE setCurrentPlayer
NOTIFY currentPlayerChanged)
signals:
void currentPlayerChanged(Player);
void gameOver(TicTacToeWidget::Player);
public slots:
void handleButtonClick(int index);
private:
Player checkWinConditionForLine(const QList<int>& line);
Player checkWinCondition();
void buttonsResizeEvent();
public:
TicTacToeWidget(QWidget *parent = nullptr);
~TicTacToeWidget();
private:
int m_boardSize;
QGridLayout *gridLayout;
QList<QPushButton*> board;
Player m_currentPlayer;
public:
void setupBoard(int size=3);
void initNewGame();
Player currentPlayer() const;
void setCurrentPlayer(Player p);
};
#endif // TICTACTOEWIDGET_H
tictactoewidget.cpp ( źródło podanych fragmentów )
#include "tictactoewidget.h"
#include "ui_tictactoewidget.h"
#include <QPushButton>
#include <QGridLayout>
#include <QSignalMapper>
#include <QLayoutItem>
#include <QResizeEvent>
///-------------------------------------------------------------------------
void TicTacToeWidget::handleButtonClick(int index) {
if(index<0 || index>=board.size()) return;
QPushButton *button = board.at(index);
if(button->text() != " ") return;
button->setText(currentPlayer() == Player1 ? "X" : "O");
Player winner = checkWinCondition();
if(winner==Invalid) {
setCurrentPlayer(currentPlayer()==Player1 ? Player2 : Player1);
return;
} else {
emit gameOver(winner);
}
}
TicTacToeWidget::Player TicTacToeWidget::checkWinConditionForLine(
const QList<int>& line) {
QString text1 = board[line[0]]->text();
if(text1==" ")
return Invalid;
bool correct = true;
for(int i=1; i<line.size(); ++i){
if(text1 != board[line[i]]->text()){
correct = false;
break;
}
}
if(correct)
return text1=="X" ? Player1 : Player2;
return Invalid;
}
///-------------------------------------------------------------------------
TicTacToeWidget::Player TicTacToeWidget::checkWinCondition() {
Player result = Invalid;
QList<int> line;
for(int row=0; row<m_boardSize; ++row) {
for(int column=0; column<m_boardSize; ++column) {
line.append(m_boardSize*row+column);
}
result = checkWinConditionForLine(line);
line.clear();
if(result!=Invalid)
return result;
}
line.clear();
for(int column=0; column<m_boardSize; ++column) {
for(int row=0; row<m_boardSize; ++row){
line.append(m_boardSize*row+column);
}
result = checkWinConditionForLine(line);
line.clear();
if(result!=Invalid)
return result;
}
line.clear();
int actualIndex = 0;
for(int i=0; i<m_boardSize; ++i){
line.append(actualIndex);
actualIndex += (m_boardSize+1);
}
result = checkWinConditionForLine(line);
if (result != Player::Invalid)
return result;
line.clear();
actualIndex = m_boardSize-1;
for(int i=0; i<m_boardSize; ++i){
line.append(actualIndex);
actualIndex += (m_boardSize-1);
}
result = checkWinConditionForLine(line);
if (result != Player::Invalid)
return result;
for(QPushButton *button : board)
if(button->text()==" ")
return Invalid;
return Draw;
}
///------------------------------------------------------------------------- jhhj
void TicTacToeWidget::buttonsResizeEvent(){
for(int i=0; i<board.size(); ++i){
QPushButton* button = board.at(i);
int size = button->geometry().height();
QFont font = button->font();
font.setPointSize(size/2);
button->setFont(font);
}
}
///-------------------------------------------------------------------------
TicTacToeWidget::TicTacToeWidget(QWidget *parent)
: QWidget(parent) {
gridLayout = new QGridLayout(this);
connect(this, SIGNAL(QResizeEvent()), this, SLOT(buttonsResizeEvent()));
}
///-------------------------------------------------------------------------
TicTacToeWidget::~TicTacToeWidget() {}
void remove (QLayout* layout ) {
QLayoutItem* child;
while ( layout->count() != 0 ) {
child = layout->takeAt ( 0 );
if ( child->layout() != 0 ) {
remove ( child->layout() );
} else if ( child->widget() != 0 ) {
delete child->widget();
}
delete child;
}
}
void TicTacToeWidget::setupBoard(int size) {
board.clear();
remove(gridLayout);
m_boardSize = size;
QSignalMapper* mapper = new QSignalMapper(this);
for(int row = 0; row < m_boardSize; ++row) {
for(int column = 0; column < m_boardSize; ++column) {
QPushButton *button = new QPushButton;
button->setSizePolicy(QSizePolicy::Preferred,QSizePolicy::Preferred);
button->setText(" ");
button->setStyleSheet("font-size: 90em");
gridLayout->addWidget(button, row, column);
board.append(button);
mapper->setMapping(button, board.count()-1);
connect(button, SIGNAL(clicked()), mapper, SLOT(map()));
}
}
connect(mapper, SIGNAL(mapped(int)), this, SLOT(handleButtonClick(int)));
setLayout(gridLayout);
}
///-------------------------------------------------------------------------
void TicTacToeWidget::initNewGame() {
for(int i=0; i<board.size(); ++i) board.at(i)->setText(" ");
}
///-------------------------------------------------------------------------
TicTacToeWidget::Player TicTacToeWidget::currentPlayer() const {
return m_currentPlayer;
}
///-------------------------------------------------------------------------
void TicTacToeWidget::setCurrentPlayer(TicTacToeWidget::Player p) {
if(m_currentPlayer == p) return;
m_currentPlayer = p;
emit currentPlayerChanged(p);
}
Nie dałem kodu dla okienka konfiguracyjnego bo chyba nie ma sensu. Z góry dziękuje i pozdrawiam :)