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.5k 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 Frederick Virchanza Gotham

    First thing I need to do is pick a very simple Qt plugin to try load into my wxWidgets program. What about the following?

    https://ftp.nmr.mgh.harvard.edu/pub/dist/freesurfer/tutorial_versions/freesurfer/lib/qt/qt_doc/html/designer-customwidgetplugin.html

    Or is there a more suitable candidate?

    Pl45m4P Online
    Pl45m4P Online
    Pl45m4
    wrote on last edited by
    #4

    I still don't see the reason to mix Qt (Widgets) and wxWidgets... or even this:

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

    I think it would be even cooler to be able to load a Qt plugin that draws widgets into a wxWidgets program

    but feel free to do it :)


    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 Frederick Virchanza Gotham
      #5

      Glad I have your support @Pl45m4 :-)

      Okay so I'm looking at the plugin example here: https://doc.qt.io/qt-6.2/qtwidgets-tools-echoplugin-example.html

      It shows how to load the plugins into the main app:

      bool EchoWindow::loadPlugin()
      {
          QDir pluginsDir(QCoreApplication::applicationDirPath());
          QStringList const entries = pluginsDir.entryList(QDir::Files);
      
          for ( QString const &fileName : entries )
          {
              QPluginLoader pluginLoader(  pluginsDir.absoluteFilePath(fileName)  );
              QObject *plugin = pluginLoader.instance();
              if ( nullptr == plugin ) continue;
              echoInterface = qobject_cast<EchoInterface *>(plugin);
              if ( echoInterface ) return true;
              pluginLoader.unload();
          }
      
          return false;
      }
      

      The only thing missing is that this plugin doesn't draw any widgets. Does anyone have a link to a Qt plugin example that draws widgets (sort of like how you'd load an ActiveX control into a Win32 program)?

      Or shall we edit this example to draw widgets? Here's how the plugin interface looks so far:

      class EchoInterface
      {
      public:
          virtual ~EchoInterface() = default;
          virtual QString echo(const QString &message) = 0;
      };
      
      #define EchoInterface_iid "org.qt-project.Qt.Examples.EchoInterface"
      
      Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid)
      

      So would I need to add a method that draws the widgets and connects their handlers? Something like the following:

      class EchoInterface
      {
      public:
          virtual ~EchoInterface() = default;
          virtual QString echo(const QString &message) = 0;
          virtual bool DrawWidgets( QWidget &parent, QGridLayout &layout ) = 0;
      };
      
      #define EchoInterface_iid "org.qt-project.Qt.Examples.EchoInterface"
      
      Q_DECLARE_INTERFACE(EchoInterface, EchoInterface_iid)
      

      And how would the implementation of this method look? Would it be something like the following?

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

      Am I on the right track so far? The main program has a tab control, and when you click on a different tab, it shows a different plugin. Note that the plugin draws the widgets on a pre-existing window -- i.e. on the tab control, and that it does not actually create a new dialog box on the screen.

      Here's how the main program looks, it has a tab for each plugin:

      93f775bd-c465-4d31-b441-3d0698135397-image.png

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

        Guys it's like pulling teeth trying to get Qt Creator to run on Ubuntu. I installed it from the Ubuntu Software app and now I'm looking through guides on the web to try figure out how to fix it. It doesn't work out of the box. I'm running Ubuntu 24.04 and Qt Creator 13.0.2. I've already fixed the 'qmake' problem , and now I've moved onto solving the 'No QML Utility installed' problem.

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

          Also I'm looking here at the implementation of QCoreApplication::exec which I've simplified to:

          int QCoreApplication::exec()
          {
              QEventLoop eventLoop;
              return eventLoop.exec();
          }
          

          Inside the implementation of QEventLoop::exec, it calls loadAcquire and also processEvents.

          I'm not sure yet but I might have to edit the source code for the wxWidgets library so that when it gets a message which it doesn't recognise, it forwards it on to something along the lines of QEventLoop::processEvents. Although, I'm not entirely sure if this will be necessary (because it wasn't necessary to do so in order to accommodate DotNet plugins written in C# and Visual Basic, nor was it necessary to accommodate ActiveX controls from OCX files).

          In the meantime I'm still trying to install Qt Creator but I'm busy resizing my virtual machine because the Qt installer is telling me it needs tens of gigs of freespace.

          If anyone could please tell me if I'm barking up the tree with the method I've written called DrawWidgets:

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

          Is this how a Qt plugin show draw widgets on a pre-exisiting window (e.g. in a tab control)?

          1 Reply Last reply
          0
          • 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 Offline
              JonBJ Offline
              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 Online
                Pl45m4P Online
                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