Results 1 to 17 of 17

Thread: Really strange problem with custom QGraphicsWidget

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Question Really strange problem with custom QGraphicsWidget

    I'm making a pretty basic board game (based on a grid of squares) with Qt on top of a QGraphicsView, and I'm implementing the game board manually in its own QGraphicsWidgets (due to not being able to tell the view not to scale and translate a given widget), which means I need to handle all the rendering and logic myself. Which so far hasn't been that much trouble, but I'm stuck with one bug (likely in my own code) that I just haven't been able to solve.

    Basically, when I use the mouse wheel to zoom, my game board will zoom in and out, but occasionally the squares will render a little too small but otherwise everything looks fine, no gaps between the squares, and the outline I draw right after the squares is the right size. Even the trace log says the squares are the right size, yet things aren't quite right regardless.

    If someone could help me look through my problem I'd be greatfull. I've attached the files for my custom widget, its a bit of a mess, but is pretty straight forward for the most part.

    I'm also interested in ideas on how to improve the internal structure of the widget if anyone has ideas.

    append: Should have done this originally, but I'm pasting just the few functions (slightly cleaned up) that I think matter in this case from the sources attached:

    Qt Code:
    1. void GameBoard::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget */* widget */)
    2. painter->save();
    3. painter->translate(geometry().width()/2.0, geometry().height()/2.0);
    4.  
    5. int piece_size_tf = ceil(piece_size * zoom);
    6.  
    7. QPointF board_off = QPointF((qreal)board_w / 2.0 * piece_size_tf, (qreal)board_h / 2.0 * piece_size_tf);
    8. QPointF board_pos = QPointF((qreal)board_w * piece_size_tf * x_scroll, (qreal)board_h * piece_size_tf * y_scroll) - board_off;
    9. QSizeF board_size = QSizeF(piece_size_tf * (qreal)board_w, piece_size_tf * (qreal)board_h);
    10.  
    11. board_pos.setX(qRound(board_pos.x()));
    12. board_pos.setY(qRound(board_pos.y()));
    13.  
    14. board_size.setWidth(qRound(board_size.width()));
    15. board_size.setHeight(qRound(board_size.height()));
    16.  
    17. QRectF board_geometry = QRectF(board_pos, board_size);
    18.  
    19. for(int i = 0; i < board_h; i++)
    20. {
    21. for(int j = 0; j < board_w; j++)
    22. {
    23. QRectF geom = board[i][j]->getGeometry();
    24. geom.setLeft(qRound(geom.left() * zoom));
    25. geom.setTop(qRound(geom.top() * zoom));
    26. geom.setRight(qRound(geom.right() * zoom));
    27. geom.setBottom(qRound(geom.bottom() * zoom));
    28.  
    29. painter->save();
    30.  
    31. painter->translate(board_pos + geom.topLeft());
    32. board[i][j]->paint(painter, QSize(geom.width(), geom.height()));
    33. painter->restore();
    34. }
    35. }
    36.  
    37. painter->drawRect(board_geometry);
    38. painter->restore();
    39. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. void GameBoard::wheelEvent(QGraphicsSceneWheelEvent * event)
    2. {
    3. qDebug("GameBoard::wheelEvent: %i", event->delta());
    4. qDebug("GameBoard::wheelEvent:before zoom:%f piece_size:%i", zoom, piece_size);
    5.  
    6. int delta = event->delta();
    7.  
    8. int piece_size_tf = qRound((qreal)piece_size * zoom);
    9. if(delta < 0 && // zoom in, if board is smaller than the view, just ignore event
    10. piece_size_tf * board_w < geometry().width() &&
    11. piece_size_tf * board_h < geometry().height()) {
    12. qDebug("zoom bestfit: %f", zoom);
    13. return;
    14. }
    15.  
    16. qreal best_fit_scale = qMin<qreal>(((qreal)geometry().width())/((qreal)board_w * (qreal)piece_size), ((qreal)geometry().height())/((qreal)board_h * (qreal)piece_size));
    17. best_fit_scale = 0.1 * qRound( (best_fit_scale-0.05) * 10.0 );
    18. if(best_fit_scale < 0.0 || best_fit_scale > 4) {
    19. qDebug("scale: out of range: %f", best_fit_scale);
    20. }
    21.  
    22. qDebug("zoom +- %f (%d)", delta/1200.0, delta);
    23. if(delta > 0) { // zoom in, love these magic numbers.
    24. if(zoom+(delta/1200.0) > 4.0) {
    25. qDebug("can't zoom in, too close already");
    26. zoom = 4.0;
    27. }
    28. else {
    29. zoom += delta / 1200.0;
    30. }
    31. }
    32. else { // zoom out
    33. if(zoom+(delta/1200.0) < best_fit_scale) {
    34. qDebug("can't zoom out, too far out");
    35. zoom = best_fit_scale;
    36. }
    37. else {
    38. zoom += delta / 1200.0;
    39. }
    40. }
    41.  
    42. update();
    43. }
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. void GameBoardSquare::paint ( QPainter * painter, QSize size )
    2. {
    3. //qDebug("GameBoardSquare::paint!");
    4. QRect rect = QRect(0, 0, size.width(), size.height());
    5.  
    6. //qDebug() << "GameBoardSquare::paint: " << pos() << size();
    7. if(flags & Filled) {
    8. if(flags & FilledS) {
    9. image->paint(painter, rect, "s_square");
    10. }
    11. else {
    12. image->paint(painter, rect, "o_square");
    13. }
    14. }
    15. else {
    16. image->paint(painter, rect, "empty_square");
    17.  
    18. if(flags & LetterSelectOHover) {
    19. image->paint(painter, rect, "o_highlight");
    20. }
    21. else if(flags & LetterSelectSHover) {
    22. image->paint(painter, rect, "s_highlight");
    23. }
    24. }
    25. }
    To copy to clipboard, switch view to plain text mode 
    Attached Files Attached Files
    Last edited by Tomasu; 14th April 2010 at 16:14. Reason: added some relevant source inline

  2. #2
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    17
    Thanked 90 Times in 88 Posts

    Default Re: Really strange problem with custom QGraphicsWidget

    Hi there!

    Sorry no time to look through >20kb of code right now.

    QGraphicsItem::ItemIgnoresTransformations doesn't work for you?

    Johannes

  3. #3
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Really strange problem with custom QGraphicsWidget

    Quote Originally Posted by JohannesMunk View Post
    Hi there!

    Sorry no time to look through >20kb of code right now.

    QGraphicsItem::ItemIgnoresTransformations doesn't work for you?

    Johannes
    It doesn't ignore translations. So sadly it doesn't work for me.

  4. #4
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Really strange problem with custom QGraphicsWidget

    I've updated my original post with the most (i think) relevant source to the problem.

  5. #5
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Really strange problem with custom QGraphicsWidget

    I'm really stuck here. I've been trying to figure this out for the past few days now (along with other problems that got fixed), but this one little bug is annoying the crap out of me. Everything I can think of hasn't fixed it, its taunting me

    I can't figure it out. if someone could spare some time to take a look at this with me I'd appreciate it.

  6. #6
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    17
    Thanked 90 Times in 88 Posts

    Default Re: Really strange problem with custom QGraphicsWidget

    Hi there!

    1. Why do you round your rect? Just use QRectF throughout. QPainter has overloaded methods for the floating point types.

    2. If that doesn't solve it, can you provide a screenshot and a minimal compilable example, that reproduces your problem?

    Johannes

  7. #7
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Really strange problem with custom QGraphicsWidget

    Using floating point coordinates causes slight movement in the individual components in the game board and the board itself. They shift a pixel somewhat randomly. My original implementation used nothing but floats because it was convenient, but it caused slight rendering glitches when the board was scaled, resized and translated.

    Here's a screenshot of two instances, the one in the bg is the way it should look, and the foreground one is how it can sometimes appear. Note that the black outline is drawn using the same variables in the same function as the squares, so if one is wrong, they both should be.



    A minimal example will take some time to put together. Right now the that is part of a larger client program, and I'd have to start a new skeleton QGraphicsView application to make the example. Probably get it posted later today.

    Thanks

  8. #8
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    17
    Thanked 90 Times in 88 Posts

    Default Re: Really strange problem with custom QGraphicsWidget

    Hi!

    I can't see why floating point values should produce rendering glitches.. the graphicsscene has to use floats internally..

    Try this.. Then the squares geometry is really based upon the same rect!

    Qt Code:
    1. void GameBoard::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget */* widget */)
    2. painter->save();
    3. painter->translate(geometry().width()/2.0, geometry().height()/2.0);
    4.  
    5. //int piece_size_tf = ceil(piece_size * zoom);
    6. double piece_size_tf = piece_size * zoom;
    7.  
    8. QPointF board_off = QPointF((qreal)board_w / 2.0 * piece_size_tf, (qreal)board_h / 2.0 * piece_size_tf);
    9. QPointF board_pos = QPointF((qreal)board_w * piece_size_tf * x_scroll, (qreal)board_h * piece_size_tf * y_scroll) - board_off;
    10. QSizeF board_size = QSizeF(piece_size_tf * (qreal)board_w, piece_size_tf * (qreal)board_h);
    11.  
    12. //board_pos.setX(qRound(board_pos.x()));
    13. //board_pos.setY(qRound(board_pos.y()));
    14.  
    15. //board_size.setWidth(qRound(board_size.width()));
    16. //board_size.setHeight(qRound(board_size.height()));
    17.  
    18. QRectF board_geometry = QRectF(board_pos, board_size);
    19.  
    20. for(int i = 0; i < board_h; i++)
    21. {
    22. for(int j = 0; j < board_w; j++)
    23. {
    24. //QRectF geom = board[i][j]->getGeometry();
    25. //geom.setLeft(qRound(geom.left() * zoom));
    26. //geom.setTop(qRound(geom.top() * zoom));
    27. //geom.setRight(qRound(geom.right() * zoom));
    28. //geom.setBottom(qRound(geom.bottom() * zoom));
    29. QRectF geom(j*piece_size_tf,i*piece_size_tf,piece_size_tf,piece_size_tf);
    30.  
    31. painter->save();
    32.  
    33. painter->translate(board_pos + geom.topLeft());
    34. board[i][j]->paint(painter, QSizeF(geom.width(), geom.height()));
    35. painter->restore();
    36. }
    37. }
    38.  
    39. painter->drawRect(board_geometry);
    40. painter->restore();
    41. }
    To copy to clipboard, switch view to plain text mode 
    HIH

    Joh

  9. #9
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    17
    Thanked 90 Times in 88 Posts

    Default Re: Really strange problem with custom QGraphicsWidget

    When I step back twice.. I'm really not happy with your approach. Zooming, Scrolling ... all that can be handled entirely by the scene/view. By applying the right transformations..

    Why are you doing it manually?

    Johannes

  10. #10
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Really strange problem with custom QGraphicsWidget

    Quote Originally Posted by JohannesMunk View Post
    When I step back twice.. I'm really not happy with your approach. Zooming, Scrolling ... all that can be handled entirely by the scene/view. By applying the right transformations..

    Why are you doing it manually?

    Johannes
    I plan to use QGraphicsWidgets to display user interface elements on top of the board, but I can't have those be translated or transformed. QGraphicsView doesn't allow me to make a QGraphicsItem/Widget that ignores both the translation and transform.

    My first attempt at this widget just used QGV's own scaling and transforms. It worked fine for that, but I can't get item's to ignore the transform and translate.

  11. #11
    Join Date
    Feb 2007
    Location
    Karlsruhe, Germany
    Posts
    469
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows
    Thanks
    17
    Thanked 90 Times in 88 Posts

    Default Re: Really strange problem with custom QGraphicsWidget

    Why don't you do it like this:

    Qt Code:
    1. #ifndef GAMEBOARD_H
    2. #define GAMEBOARD_H
    3.  
    4. #include <QtGui>
    5.  
    6. class CheckerBoardSQ : public QGraphicsItem
    7. {
    8. public:
    9. CheckerBoardSQ(QGraphicsItem *parent = 0,QGraphicsScene *scene = 0) : QGraphicsItem(parent,scene) {}
    10. static qreal size() {return 20;}
    11. QRectF boundingRect() const
    12. {
    13. qreal penWidth = 1;
    14. return QRectF(-penWidth/2,-penWidth/2,size() + penWidth,size() + penWidth);
    15. }
    16. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    17. {
    18. painter->drawRoundedRect(0,0,size(),size(), 5, 5);
    19. }
    20. };
    21.  
    22. class CheckerBoard : public QGraphicsItem
    23. {
    24. public:
    25. CheckerBoard(int n_x,int n_y,QGraphicsItem *parent = 0,QGraphicsScene *scene = 0) : QGraphicsItem(parent,scene)
    26. {
    27. m_n_x = n_x;m_n_y = n_y;
    28. for (int i = 0;i < n_x;++i)
    29. {
    30. for (int j = 0;j < n_y;++j)
    31. {
    32. CheckerBoardSQ* sq = new CheckerBoardSQ(this);
    33. sq->setPos(i*CheckerBoardSQ::size(),j*CheckerBoardSQ::size());
    34. }
    35. }
    36. }
    37. QRectF boundingRect() const
    38. {
    39. qreal penWidth = 1;
    40. return QRectF(-penWidth/2,-penWidth/2,m_n_x*CheckerBoardSQ::size() + penWidth,m_n_y*CheckerBoardSQ::size() + penWidth);
    41. }
    42. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    43. {
    44. painter->drawRect(0,0,m_n_x*CheckerBoardSQ::size(),m_n_y*CheckerBoardSQ::size());
    45. }
    46. private:
    47. int m_n_x;
    48. int m_n_y;
    49. };
    50.  
    51. class MainWidget : public QWidget
    52. {
    53. public:
    54. MainWidget() {
    55. scene = new QGraphicsScene();
    56. scene->addItem(new CheckerBoard(8,8));
    57.  
    58. view = new QGraphicsView(scene);
    59.  
    60. QVBoxLayout* vl = new QVBoxLayout();
    61. vl->addWidget(view);
    62.  
    63. setLayout(vl);
    64. }
    65. void keyPressEvent (QKeyEvent * event)
    66. {
    67. if (event->text() == "+") {
    68. view->scale(1.1,1.1);
    69. event->accept();
    70. }
    71. if (event->text() == "-") {
    72. view->scale(0.90,0.90);
    73. event->accept();
    74. }
    75. if (event->text() == "#") {
    76. view->resetTransform();
    77. event->accept();
    78. }
    79. }
    80.  
    81. private:
    82. };
    83.  
    84. #endif // GAMEBOARD_H
    85.  
    86. --------------------
    87.  
    88. #include <QtCore>
    89. #include <QtGui>
    90. #include "gameboard.h"
    91.  
    92. int main(int argc, char *argv[])
    93. {
    94. QApplication a(argc, argv);
    95.  
    96. MainWidget wdg;
    97. wdg.show();
    98.  
    99. QObject::connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()));
    100.  
    101. return a.exec();
    102. }
    To copy to clipboard, switch view to plain text mode 

    Where is the problem with the translation?

    Johannes

  12. #12
    Join Date
    Jan 2006
    Posts
    10
    Qt products
    Qt3 Qt4
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: Really strange problem with custom QGraphicsWidget

    I've tried to apply that, It does seem to get rid of the problem I was trying to fix, but it reintroduces the prior rendering glitches.



    And they appear at about the same times when the size bug would happen.

    If it helps, the board is drawn using Svgs cached in QPixmaps, so no piece can even have a floating point size, so the board's over all geometry also can't have a fractional size. Using floating point math, subtle inacuracy is introduced, causing gaps. Or at least thats how I see it so far. And rounding the final calculated geometry fixes the gap issue, but introduces the size issue. Which is strange, because I have a printf outputing the Square's geometries in that inner paint loop, and they /look/ fine. They aren't a pixel off, and yet things are still drawing wrong.

    Thanks again.

Similar Threads

  1. Replies: 0
    Last Post: 2nd February 2010, 13:10
  2. Strange problem
    By wirasto in forum Qt Programming
    Replies: 3
    Last Post: 27th December 2009, 12:24
  3. Strange problem
    By pavel in forum Newbie
    Replies: 4
    Last Post: 18th December 2009, 22:46
  4. Very Strange problem
    By dreamer in forum Qt Programming
    Replies: 1
    Last Post: 30th April 2008, 10:20

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.