PDA

View Full Version : Emit Signal and Slot question



kev.nam
2nd June 2011, 16:31
Hi, I'm new to Qt (and GUI in general) and I'm trying to make a board game with 19x19 squares. They way I'm trying to do this is with 19x19 = 361 QLabel widgets, each with an empty square picture. Then when I want to place a stone at a square, I emit a signal to a slot that changes the PixMap of the QLabel at that square:


void MainWidget::placeStone(int y,int x, char colour){

if (colour == 'D'){
board[y][x]->setPixmap(QPixmap("black.png"));
} else {
board[y][x]->setPixmap(QPixmap("white.png"));
}
return;
}


My Class:


class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);

public slots:
void placeStone(int y,int x, char colour);
void moveNotMade(){}
void invalidPort();



private:
QLabel* board [19][19];
};

The constructor:



MainWidget::MainWidget(QWidget *parent) : QWidget(parent)
{
QPushButton *quit = new QPushButton(tr("Quit"));
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
myProg* program1 = new myProg();

/// PORT INPUT
QLabel *portInputLabel = new QLabel();
portInputLabel->setText("Port (ex: /dev/ttyS0):");
portInputLabel->setAlignment(Qt::AlignRight);
QLineEdit* portInput = new QLineEdit();
connect(portInput,SIGNAL(textChanged(QString)),pro gram1,SLOT(getPort(QString)));

/// COLOUR INPUT
QLabel *colourInputLabel = new QLabel();
colourInputLabel->setText("Software AI Colour (dark or light):");
colourInputLabel->setAlignment(Qt::AlignRight);
QLineEdit* colourInput = new QLineEdit();
connect(colourInput,SIGNAL(textChanged(QString)),p rogram1,SLOT(getColour(QString)));

QGridLayout *grid = new QGridLayout;
grid->addWidget(portInputLabel,1,1);
grid->addWidget(portInput,1,2);
grid->addWidget(colourInputLabel,2,1);
grid->addWidget(colourInput,2,2);

setUpdatesEnabled(true);

QPushButton *startButton = new QPushButton(tr("Start"));
connect(startButton, SIGNAL(clicked()),program1,SLOT(startProgram()));


QGridLayout *grid1 = new QGridLayout;
for (int row = 0; row < 19; ++row) {
for (int column = 0; column < 19; ++column) {
board[row][column] = new QLabel();
board[row][column]->setPixmap(QPixmap("empty.png"));
board[row][column]->adjustSize();
grid1->addWidget(board[row][column], row, column);
}
}
grid1->setHorizontalSpacing(0);
grid1->setVerticalSpacing(0);

connect(program1,SIGNAL(placeStone(int,int,char)), this,SLOT(placeStone(int,int,char)),Qt::DirectConn ection);
connect(program1,SIGNAL(refreshScreen()),this,SLOT (update()),Qt::DirectConnection);

QVBoxLayout *layout = new QVBoxLayout;
layout->addLayout(grid);
layout->addWidget(quit);
layout->addWidget(startButton);
layout->addLayout(grid1);
setLayout(layout);
}

My Issue is that the placeStone slot only seems to take place AFTER the function that emits the signal returns. I've tried changing the connection type to Qt::DirectConnection, but that did not change anything. I've also tried calling the update() function to force it to update the screen, but that didn't help

Thanks in advance!

Lykurg
2nd June 2011, 16:57
Can we see the function, that emits the signal? Also update() won't change anything, because
This function does not cause an immediate repaint; instead it schedules a paint event for processing when Qt returns to the main event loop.
I guess it is the same with the setPixmap function since it probably also use update().

Maybe a QGraphicsView with 361 items is better than the overhead of 361 labels which only displays an image.

kev.nam
2nd June 2011, 17:07
Hi Lykurg, thanks for your response.

The function that is emitting is just a test function:


void myProg::startProgram(){
sleep(2);

emit placeStone(1,1,'D');

sleep(2);

emit placeStone(2,2,'L');

sleep(2);

emit placeStone(3,3,'D');

}

Instead of 1 appearing every 2 seconds, the program waits a total of 6~ seconds then outputs 3 stones at once.

Anyway, I will look into the QGraphicsView. thanks!

Lykurg
2nd June 2011, 18:06
That's because sleep blocks the main gui, thus no update() is processed. To just make sure, that your slot is actually called, add
QQCoreApplication::processEvents();after the emits to force the pending updates to be processed.

DanH
3rd June 2011, 02:55
Never sleep() in the main UI thread. If you need to time operations, use a QTimer or one if it's kin.

Note that for what you've done so far there's no need to use signal/slot -- you can just call your method. Though you'd probably want to use signals/slots with QTimer.

You need to understand how virtually all GUI systems work: You set up the details of how you want your interface presented, then "return" to an "event loop" where the actual work takes place. If you never return, the work never takes place. This is why you should never "sleep" -- not only does your work not get done, but any other operations that need to occur are also blocked (possibly including "system" work on behalf of the phone itself, when working on a phone/tablet platform).