Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. GUI program accepts various kinds of GUI plugin
Forum Updated to NodeBB v4.3 + New Features

GUI program accepts various kinds of GUI plugin

Scheduled Pinned Locked Moved Unsolved General and Desktop
18 Posts 3 Posters 1.3k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    Frederick Virchanza Gotham
    wrote on last edited by Frederick Virchanza Gotham
    #8

    For simplicity at the beginning, here's how I'll code the 'DrawWidgets' method:

    bool EchoInterface::DrawWidgets(void *const parent_native)
    {
        auto *const parent = QWindow::fromWinId(parent_native);
    
        auto *const button = new QPushButton(  tr("Click me!")  );
    
        connect( button, &QPushButton::clicked, parent, &EchoInterface::ButtonClickHandler );
    
        auto *const layout = new QGridLayout;
        layout->addWidget(button, 2, 1, Qt::AlignRight);
        layout->setSizeConstraint(QLayout::SetFixedSize);
    
        parent->setLayout(layout);
    }
    

    This might actually be a lot easier than I first thought -- I mean 2 or 3 days works instead of 2 or 3 weeks work.

    For the timebeing I'm still downloading Qt Creator (I had to move my virtual machine to a terrabyte hard disk to resize it).

    JonBJ Pl45m4P 2 Replies Last reply
    0
    • F Frederick Virchanza Gotham

      For simplicity at the beginning, here's how I'll code the 'DrawWidgets' method:

      bool EchoInterface::DrawWidgets(void *const parent_native)
      {
          auto *const parent = QWindow::fromWinId(parent_native);
      
          auto *const button = new QPushButton(  tr("Click me!")  );
      
          connect( button, &QPushButton::clicked, parent, &EchoInterface::ButtonClickHandler );
      
          auto *const layout = new QGridLayout;
          layout->addWidget(button, 2, 1, Qt::AlignRight);
          layout->setSizeConstraint(QLayout::SetFixedSize);
      
          parent->setLayout(layout);
      }
      

      This might actually be a lot easier than I first thought -- I mean 2 or 3 days works instead of 2 or 3 weeks work.

      For the timebeing I'm still downloading Qt Creator (I had to move my virtual machine to a terrabyte hard disk to resize it).

      JonBJ Online
      JonBJ Online
      JonB
      wrote on last edited by
      #9

      @Frederick-Virchanza-Gotham
      FYI, the Qt libraries and Qt Creator compiled and supplied for Ubuntu 24.04 via apt (I never go to Qt site) work, are readily available, take a few minutes to download, don't occupy terrabytes. I have always installed Qt like this through every Ubuntu version. No compiling and no source code.

      1 Reply Last reply
      1
      • F Frederick Virchanza Gotham

        For simplicity at the beginning, here's how I'll code the 'DrawWidgets' method:

        bool EchoInterface::DrawWidgets(void *const parent_native)
        {
            auto *const parent = QWindow::fromWinId(parent_native);
        
            auto *const button = new QPushButton(  tr("Click me!")  );
        
            connect( button, &QPushButton::clicked, parent, &EchoInterface::ButtonClickHandler );
        
            auto *const layout = new QGridLayout;
            layout->addWidget(button, 2, 1, Qt::AlignRight);
            layout->setSizeConstraint(QLayout::SetFixedSize);
        
            parent->setLayout(layout);
        }
        

        This might actually be a lot easier than I first thought -- I mean 2 or 3 days works instead of 2 or 3 weeks work.

        For the timebeing I'm still downloading Qt Creator (I had to move my virtual machine to a terrabyte hard disk to resize it).

        Pl45m4P Offline
        Pl45m4P Offline
        Pl45m4
        wrote on last edited by
        #10

        @Frederick-Virchanza-Gotham said in GUI program accepts various kinds of GUI plugin:

        auto *const parent = QWindow::fromWinId(parent_native);
        

        Hi,

        note that QWindow::fromWinId creates a QWindow which most likely does't match your usage here:
        parent, &EchoInterface::ButtonClickHandler

        Also when grabbing a non-Qt window, the window should't be modified via the obtained window handle.

        As:

        Note: The resulting QWindow should not be used to manipulate the underlying native window (besides re-parenting), or to observe state changes of the native window. Any support for these kind of operations is incidental, highly platform dependent and untested.
        ( https://doc.qt.io/qt-6/qwindow.html#fromWinId )


        If debugging is the process of removing software bugs, then programming must be the process of putting them in.

        ~E. W. Dijkstra

        1 Reply Last reply
        0
        • F Offline
          F Offline
          Frederick Virchanza Gotham
          wrote on last edited by
          #11

          I'm having great difficulty getting Qt to draw widgets on a native window (hereafter referred to as the 'top-level window').
          If the top-level window is a QWidget with a QVBoxLayout, then of course I can just get the shared library to create widgets with the QWidget as the parent, and add them to the layout. No problem there.
          If the shared library only has a QWindow to deal with (instead of a QWidget) then I can get the shared library to draw widgets, but only if the QWindow is actually a top-level window. If the QWindow is for some sort of 'panel' on the main window, it won't draw controls.
          And as for using 'fromWndId' with 'createWindowContainer' -- well when I try to draw the widgets, it invariably creates another top-level window.

          It's looking like I'm gonna need to look very closely at how the QWidget is implemented, and I'm going to have to manually manipulate the Qt window/widget record system to fool it into thinking that the native window handle it has been given was actually created by Qt.

          1 Reply Last reply
          0
          • F Offline
            F Offline
            Frederick Virchanza Gotham
            wrote on last edited by
            #12

            Yeah I'm looking at manually filling out one of these to try fool Qt into thinking a native window is a Qt window:

            class QWidgetData
            {
            public:
                WId winid;
                uint widget_attributes;
                Qt::WindowFlags window_flags;
                uint window_state : 4;
                uint focus_policy : 4;
                uint sizehint_forced :1;
                uint is_closing :1;
                uint in_show : 1;
                uint in_set_window_state : 1;
                mutable uint fstrut_dirty : 1;
                uint context_menu_policy : 3;
                uint window_modality : 2;
                uint in_destructor : 1;
                uint unused : 13;
                QRect crect;
                mutable QPalette pal;
                QFont fnt;
                QRect wrect;
            };
            
            1 Reply Last reply
            0
            • F Offline
              F Offline
              Frederick Virchanza Gotham
              wrote on last edited by
              #13

              Actually now I'm considering drawing one top-level window on top of another top-level window:

              https://stackoverflow.com/questions/16929090/displaying-a-qt-widget-on-overlaying-a-3rd-party-window-in-windows

              1 Reply Last reply
              0
              • F Offline
                F Offline
                Frederick Virchanza Gotham
                wrote on last edited by
                #14

                The tactic of drawing one top-level window on top of another is working for me here on Linux X11 . . . but now I need to find a way to have two event loops running together (I need my main event loop to somehow pick out the Qt events and forward them to the Qt event handlers).

                1 Reply Last reply
                0
                • F Offline
                  F Offline
                  Frederick Virchanza Gotham
                  wrote on last edited by
                  #15

                  Look what I got working today. The Qt plugin puts the button on the dialog box, and when you click the button, the Qt code shows a message box. Right now I don't know how the wxWidgets event handler system is forwarding events to the Qt library . . . but of course I'm not complaining.

                  image.png

                  1 Reply Last reply
                  0
                  • F Offline
                    F Offline
                    Frederick Virchanza Gotham
                    wrote on last edited by Frederick Virchanza Gotham
                    #16

                    Could someone please help me with something?
                    I achieved the above screenshot by getting Qt to create another top-level window without a frame and with a transparent background. So what I've got is a top-level frame with another top-level frame sitting on top of it. But of course really I just want Qt to draw the button on a pre-existing native window -- but this doesn't seem possible (I've tried all sorts of things). Perhaps could I do something like the following?
                    Step 1: Maintain a global map of QWidget objects to native handles ( e.g. std::map<QWidget*, WId> g_mywidgets; )
                    Step 2: Alter the source code of QWidget::show, make it check the aforementioned map, and if it finds the QWidget in the map, then make sure to show it as a child window placed upon the parent WId.

                    Do you reckon this could be a good strategy? Hopefully it would mean minimal alteration to the Qt library.

                    Or here's another idea:
                    Could I get the Qt code to tell me the actual pixels of the widgets it will draw? If I can get these pixels written to a simple 2-dimensional array, e.g. int pixels[1024][1024], then I could send the contents of this array to my wxWidgets main program and get the wxWidgets program to draw the pixels.

                    Anyone got any ideas please? @JonB ? @Pl45m4 ?

                    1 Reply Last reply
                    0
                    • F Offline
                      F Offline
                      Frederick Virchanza Gotham
                      wrote on last edited by Frederick Virchanza Gotham
                      #17

                      Okay I might be making a bit of progress here. I'm not sure how this will turn out but it's worth a shot. First of all, in the Qt plugin, I export a function which renders the widgets:

                      extern "C" void RenderWidgets(PixelArray_t &pixelData, int const w, int const h)
                      {
                          assert( nullptr != &pixelData );  // just for debug
                      
                          parentWidget->setGeometry(0, 0, w, h);
                      
                          QPixmap pixmap( parentWidget->size() );
                          pixmap.fill(Qt::transparent);
                      
                          QPainter painter(&pixmap);
                          parentWidget->render(&painter);
                          painter.end();
                      
                          QImage image = pixmap.toImage();
                          int const width = image.width();
                          int const height = image.height();
                          pixelData.resize( width, PixelArray_t::value_type(height) ); // 2D array of QColor
                      
                          for ( int x = 0; x < width; ++x )
                          {
                              for ( int y = 0; y < height; ++y )
                              {
                                  pixelData[x][y] = (unsigned)image.pixel(x, y);
                              }
                          }
                      }
                      

                      In my main program which runs wxWidgets, I have a handler for the Paint event for the panel, implemented as follows:

                          void OnPaint(wxPaintEvent& event)
                          {
                              wxPaintDC dc(this);   // Create a paint DC for the panel
                      
                              int const w = dc.GetSize().GetWidth ();
                              int const h = dc.GetSize().GetHeight();
                      
                              pfnRender(pixels, w, h);  // Call the function exported by the Qt plugin
                              assert( this->pixels.size()         > 0 );
                              assert( this->pixels.front().size() > 0 );
                      
                              wxBitmap bitmap(w, h);      // Create a bitmap that matches the panel size
                              wxMemoryDC memDC(bitmap);   // Create a memory DC to work with the bitmap
                      
                              for ( int x = 0; x < w; ++x )
                              {
                                  for ( int y = 0; y < h; ++y )
                                  {
                                      unsigned const pixel = pixels[x][y];
                                      unsigned char r = (pixel >> 24) & 0xFF;
                                      unsigned char g = (pixel >> 16) & 0xFF;
                                      unsigned char b = (pixel >>  8) & 0xFF;
                                      unsigned char a = (pixel >>  0) & 0xFF;
                                      memDC.SetPen( wxPen(wxColour(r, g, b), 1) );
                                      memDC.SetBrush(wxBrush(wxColour(r, g, b), wxSOLID));
                                      //memDC.SetAlpha(a);
                                      memDC.DrawRectangle(x, y, 1, 1); // Draw 1x1 pixel
                                  }
                              }
                      
                              dc.DrawBitmap(bitmap, 0, 0);
                          }
                      

                      I've tested this out and it works. So I'm able to display widgets.

                      But next . . . here's what I need to do:
                      In the wxWidgets main program, record mouse movements and mouse clicks, and send them to the Qt plugin. Then inside the Qt plugin, I need to take these movements and clicks and somehow send them to the widgets (even though the widgets aren't on screen in the canonical sense). Can anyone help me with this part?

                      1 Reply Last reply
                      0
                      • F Offline
                        F Offline
                        Frederick Virchanza Gotham
                        wrote on last edited by
                        #18

                        I've uploaded a video to YouTube showing me resizing the Qt plugin widgets in the main wxWidgets program:

                        https://www.youtube.com/watch?v=OQW1oZzn9jA

                        So now I need to figure out how to send mouse clicks and key presses from the main wxWidgets program to the Qt plugin in order for the Qt code to process the events. Not sure how I'm going to do this since Qt isn't displaying any widgets on screen (it's only rendering them in a bitmap).

                        Can I do something like the following?

                        QPoint pos(100, 100);
                        QMouseEvent event(QEvent::MouseMove, pos, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
                        QApplication::postEvent(parentWidget, event);
                        

                        The complication here is: Since Qt is not actually displaying any widgets on screen, how can it make sense of the XY coordinates I give it? So to summarise my problem is as follows:

                        I'm using Qt to render widgets into a bitmap, and then I use my wxWidgets main program to draw those widgets on the screen -- and I have this much working. But now I need to send mouse movements and key presses from wxWidgets to Qt.

                        Can someone please help me here?

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved