1 Attachment(s)
setheightforwidth not working?
Hi everybody. I've poked a bit at QT before but I'm really a newbie. Now I'm attempting to put together a version of the classic minesweeper game.
This kind of game really needs square cells in the grid. I thought I could get that by applying the "heightforwidth" property to the qpushbuttons that make up each tile.
Here's an example of what I get:
Attachment 13718
Here's the code for the cell:
Code:
{
bool Bomb;
GridPos Pos;
public:
GridCell() {}
virtual ~GridCell() {}
{
Pos = P;
GridLayout->addWidget(this, Pos.y, Pos.x);
p.setHeightForWidth (true);
p.setHorizontalStretch (1);
p.setVerticalStretch (1);
setSizePolicy (p);
setText("K");
}
void SetBomb (bool B = true)
{
Bomb = B;
}
bool IsBomb ()
{
return Bomb;
}
};
I've tried a lot of different things but guess I'm misunderstanding some fundamental concept.
A little help please?
Re: setheightforwidth not working?
Quote:
A little help please?
Your problem is with your grid layout. By design, all layouts expand to fill the widget (or layout) in which they are placed. In turn, they will expand the widgets inside them to occupy the same space by looking at things like size limits (min / max), size policy, stretch factors, spacing, margins, etc. Taking all this into account, the layout sets the size and position of the widgets it contains.
So all of the things you are doing are basically not having much effect on the actual size or shape of the widgets except to ensure that they all have the same size in the grid layout.
I'll need to think about how to implement this using widgets. It would be a lot simpler using QGraphicsScene / QGraphicsView / QGraphicsRectItem than a grid layout with push buttons. With the Graphics View architecture, you have much more control over the layout of your scene.
I think the first step is to make your left-hand panel a QHBoxLayout with a custom QWidget in the top (representing your game board) and a QSpacerItem in the bottom half. The QSpacerItem will basically force the QWidget up. Let's call it GameBoardWidget to be clear.
The GameBoardWidget needs a QGridLayout to hold the cells. Implement a sizeHint() method for the GridCell to return a square size. Set the size policies to "Preferred", not "Expanding". You'll probably also need to add a member variable for GridCell to hold the preferred size, and a method to set the preferred size.
Implement a QWidget::resizeEvent() event handler for GameBoardWidget. In this handler if GameBoardWidget::isVisible() returns true, this means that the QResizeEvent::size() method will return a valid size that can be used for geometry computations. The resizeEvent can occur multiple times while Qt is laying out the initial UI -before- anything becomes visible on screen, and the sizes in these initial calculations cannot be used. It is only after the widget is shown (isVisible returns true) that the sizes are guaranteed to be valid.
In your resize event, determine the button size based on the minimum dimension of the GameBoardWidget, the number of buttons in a row or column, and take into account the QGridLayout::horizontalSpacing() and QGridLayout::verticalSpacing(). If the new size is different from the old size, then use this number to set the size hint for your GridCell widgets, then call QWidget::updateGeometry(). Be careful you don't set up an infinite loop of resizeEvent() / updateGeometry() calls. Only change the geometry and size hints if in fact the size is different.
I can't guarantee that this will work, and I don't have time to write code to test it. You may have to play around a bit to get it all working the way you want.
1 Attachment(s)
Re: setheightforwidth not working?
Thanks for the input. I understand now that the QGridLayout needs to fill its container.
The QGraphicView approach seemed a little complicated. I really didn't want to keep track of pixels when placing the buttons.
Your resizeEvent suggestion led me to me solution. Now I'm applying the QGridLayout to a frame. I adjust the width of the frame as needed to maintain the desired aspect ratio with sizeHint.
Code:
// Special frame for playing grid
// main feature is to keep aspect ratio based on grid y/x size
class cGameGridFrame
: public QFrame {public:
// insert the new frame into the right side of the hbox layout
LO->insertWidget(0, this);
// set properties
setFrameShadow
(QFrame::Raised);
setLineWidth (4);
}
s.setWidth ((float)s.height()*GridXSize/GridYSize+0.5);
return s;
}
updateGeometry();
}
};
Example output:
Attachment 13719
Re: setheightforwidth not working?
Quote:
I really didn't want to keep track of pixels when placing the buttons.
You don't. You simply define your rectangle to have whatever dimensions you want, in logical coordinates. So if you choose a dimension of 10 x 10 for the cell, and you have a 10 x 10 grid, then you simply place each cell at increments of 10 in each direction. This would give you a QGraphicsScene with a 100 x 100 bounding box in logical, not pixel coordinates.
When you place this scene in a QGraphicsView, the view will automatically scale and translate the scene so it fits in the view. You can control this to maintain a square aspect ratio by using one of the QGraphicsView::fitInView() methods.
But it looks like you have been successful doing it with buttons and a grid layout, so whatever works. Think about the Graphics / View architecture next time you do something graphical where a grid won't work.