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
QtWS25 Last Chance

GUI program accepts various kinds of GUI plugin

Scheduled Pinned Locked Moved Unsolved General and Desktop
18 Posts 3 Posters 1.1k Views
  • 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
    #1

    I understand that wxWidgets is pretty much a rival to Qt, and vice versa, but I think it would be cool if a Qt program could accept GUI plugins written in wxWidgets, and also if a wxWidgets program could accept GUI plugins written in Qt.

    Over on the wxWidgets forum, I started a thread about this a few months ago:

    https://forums.wxwidgets.org/viewtopic.php?f=1&t=51469

    So far I've got my wxWidgets program working with four kinds of GUI plugin:
    a) wxWidgets plugins
    b) ActiveX controls (e.g. OCX file)
    c) DotNet Framework plugins (e.g. C# class library, VB class library)
    d) Any DLL file that can populate a HWND with widgets

    Next I was going to try add Java or Python to the mix . . . but I think it would be even cooler to be able to load a Qt plugin that draws widgets into a wxWidgets program -- and I realise I'll probably have to patch the wxWidgets message handling code in order to get this working.

    Are any of you here interested in this? I would appreciate some help with this, and if someone wants to write code to load wxWidgets plugins into a Qt program, then I'll assist as best I can (I've been making wxWidgets GUI programs for about 15 - 20 years). I think both the core code that handles window messages will need code added to forward messages between Qt and wxWidgets (but maybe it won't be necessary).

    Pl45m4P 1 Reply Last reply
    0
    • F Frederick Virchanza Gotham

      I understand that wxWidgets is pretty much a rival to Qt, and vice versa, but I think it would be cool if a Qt program could accept GUI plugins written in wxWidgets, and also if a wxWidgets program could accept GUI plugins written in Qt.

      Over on the wxWidgets forum, I started a thread about this a few months ago:

      https://forums.wxwidgets.org/viewtopic.php?f=1&t=51469

      So far I've got my wxWidgets program working with four kinds of GUI plugin:
      a) wxWidgets plugins
      b) ActiveX controls (e.g. OCX file)
      c) DotNet Framework plugins (e.g. C# class library, VB class library)
      d) Any DLL file that can populate a HWND with widgets

      Next I was going to try add Java or Python to the mix . . . but I think it would be even cooler to be able to load a Qt plugin that draws widgets into a wxWidgets program -- and I realise I'll probably have to patch the wxWidgets message handling code in order to get this working.

      Are any of you here interested in this? I would appreciate some help with this, and if someone wants to write code to load wxWidgets plugins into a Qt program, then I'll assist as best I can (I've been making wxWidgets GUI programs for about 15 - 20 years). I think both the core code that handles window messages will need code added to forward messages between Qt and wxWidgets (but maybe it won't be necessary).

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

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

      I understand that wxWidgets is pretty much a rival to Qt, and vice versa

      In most cases wxwidgets can't compete with the whole Qt Framework. And I don't say that because I'm a Qt user, but because it is like that ;-)

      if a Qt program could accept GUI plugins written in wxWidgets

      You can embed native Windows/content via

      • https://doc.qt.io/qt-6/qwindow.html#fromWinId

      and

      • https://doc.qt.io/qt-6/qwidget.html#createWindowContainer

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

      I don't think this will work. At least not directly.

      I would appreciate some help with this, and if someone wants to write code to load wxWidgets plugins into a Qt program, then I'll assist as best I can (I've been making wxWidgets GUI programs for about 15 - 20 years). I think both the core code that handles window messages will need code added to forward messages between Qt and wxWidgets

      So you want the Qt event loop and underlaying system send events and messages to wxWidgets handlers?!
      But why?!
      (⊙_⊙)?


      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
        #3

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