QMainWindow, no title, border



  • I have a QMainWindow which is being used to display status during a process, the Window has no title which is intended, it is also borderless, when the window is visible there is no border or distinction between the window background and windows behind it, I haven't see any flags to make the window borderless, how do I implement a border on a window that has no title?

    import.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>ImportRDF</class>
     <widget class="QMainWindow" name="ImportRDF">
      <property name="windowModality">
       <enum>Qt::ApplicationModal</enum>
      </property>
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>597</width>
        <height>108</height>
       </rect>
      </property>
      <property name="minimumSize">
       <size>
        <width>597</width>
        <height>108</height>
       </size>
      </property>
      <widget class="QWidget" name="centralWidget">
       <property name="sizePolicy">
        <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
         <horstretch>0</horstretch>
         <verstretch>0</verstretch>
        </sizepolicy>
       </property>
       <layout class="QGridLayout" name="gridLayout">
        <item row="0" column="0">
         <widget class="QLabel" name="plblRDFile">
          <property name="text">
           <string>RDF file:</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="0" column="1" colspan="3">
         <widget class="QLabel" name="plblFilename">
          <property name="text">
           <string>Device, path and filename</string>
          </property>
         </widget>
        </item>
        <item row="1" column="0">
         <widget class="QLabel" name="plblFilesizeTxt">
          <property name="text">
           <string>File size:</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="1" column="1">
         <widget class="QLabel" name="plblFilesize">
          <property name="contextMenuPolicy">
           <enum>Qt::NoContextMenu</enum>
          </property>
          <property name="text">
           <string>##########</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="1" column="2">
         <widget class="QLabel" name="plblBlocksTxt">
          <property name="text">
           <string>Blocks:</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
          </property>
         </widget>
        </item>
        <item row="1" column="3">
         <widget class="QWidget" name="gridWidget" native="true">
          <property name="contextMenuPolicy">
           <enum>Qt::NoContextMenu</enum>
          </property>
          <property name="styleSheet">
           <string notr="true">margin:0;padding:0;</string>
          </property>
          <layout class="QHBoxLayout" name="horizontalLayout">
           <property name="spacing">
            <number>0</number>
           </property>
           <property name="leftMargin">
            <number>0</number>
           </property>
           <property name="topMargin">
            <number>0</number>
           </property>
           <property name="rightMargin">
            <number>0</number>
           </property>
           <property name="bottomMargin">
            <number>0</number>
           </property>
           <item>
            <widget class="QLabel" name="plblBlock">
             <property name="text">
              <string>#######</string>
             </property>
             <property name="alignment">
              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLabel" name="plblOfTxt">
             <property name="text">
              <string> of </string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLabel" name="plblTotalBlocks">
             <property name="text">
              <string>#######</string>
             </property>
             <property name="alignment">
              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer_2">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>40</width>
               <height>20</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QLabel" name="plblChunksizeTxt">
             <property name="text">
              <string>Chunk size:</string>
             </property>
             <property name="alignment">
              <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLabel" name="plblRead">
             <property name="text">
              <string>########</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer_3">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>40</width>
               <height>20</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QLabel" name="plblBScansTxt">
             <property name="text">
              <string>BScans:</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLabel" name="plblBScans">
             <property name="text">
              <string>#####</string>
             </property>
            </widget>
           </item>
           <item>
            <spacer name="horizontalSpacer">
             <property name="orientation">
              <enum>Qt::Horizontal</enum>
             </property>
             <property name="sizeHint" stdset="0">
              <size>
               <width>40</width>
               <height>20</height>
              </size>
             </property>
            </spacer>
           </item>
           <item>
            <widget class="QLabel" name="plblElapsedTxt">
             <property name="text">
              <string>Elapsed:</string>
             </property>
            </widget>
           </item>
           <item>
            <widget class="QLabel" name="plblElapsed">
             <property name="text">
              <string>##:##:##.###</string>
             </property>
            </widget>
           </item>
          </layout>
         </widget>
        </item>
        <item row="2" column="0" colspan="4">
         <widget class="QProgressBar" name="pgbrStatus">
          <property name="value">
           <number>24</number>
          </property>
         </widget>
        </item>
        <item row="3" column="3">
         <widget class="QPushButton" name="pbtnAbort">
          <property name="minimumSize">
           <size>
            <width>80</width>
            <height>24</height>
           </size>
          </property>
          <property name="text">
           <string>&amp;Abort</string>
          </property>
         </widget>
        </item>
       </layout>
      </widget>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

    import.h

    /**
     * File:
     *  importrdf.h
     *
     * Notes:
     *  This file contains the prototype for the ImportRDF class.
     *
     * Static Constants:
     *  mscuint16BlockSize      Size of database blob / block size
     *  mscuint16UploadInterval Upload block interval in milliseconds
     *
     * Static Members:
     *  mspInstance     Pointer to instance of dialog
     *
     * Static Methods:
     *  pInstance       Access method to mspInstance
     *
     * Methods:
     *  ImportRDF       Class constructor
     *  ~ImportRDF      Class destructor
     *  closeDialog     Close the import progress dialog
     *  lngBScans       Access method to get BScans in RDF
     *  setDatasetId    Access method to set muintDatasetID
     *  startImport     Starts file import process
     *  updateElapsedTime   Updates the elapsed time display
     *
     * Members:
     *  mcnAbortClicked Connection to abort button clicked signal
     *  mdsIn           Instance of QDataStream for reading RDF
     *  metTaken        Elapsed time taken
     *  mfileRDF        Instance of QFile for reading RDF
     *  mpRDF           Pointer to RDF helper
     *  mpcBuffer       Pointer to buffer to read data block into
     *  mptmrUpload     Pointer to timer to upload data block
     *  mpui            Pointer to user interface
     *  muint64Block    Current block to upload
     *  muint64Total    Total number of blocks to upload
     *  muintDatasetID  Dataset ID of import
     *
     * Signals:
     *  importComplete  Emitted when RDF import completed
     *
     * Slots:
     *  dbError         Slot connected to Trainer::dbError signal
     *******************************************************************************
     * History
     *  17/05/2021 Written by Simon Platten
     */
    #ifndef IMPORTRDF_H
    #define IMPORTRDF_H
    
    #include <QDataStream>
    #include <QElapsedTimer>
    #include <QFile>
    #include <QLabel>
    #include <QMainWindow>
    #include <QProgressBar>
    #include <QSqlError>
    #include <QSqlQuery>
    #include <QSqlResult>
    #include <QTimer>
    
    #include "rdf.h"
    
    namespace Ui {
    class ImportRDF;
    }
    
    class ImportRDF : public QMainWindow
    {
        Q_OBJECT
    
    private:
        static const quint16 mscuint16BlockSize;
        static const quint16 mscuint16UploadInterval;
        static ImportRDF* mspInstance;
        QMetaObject::Connection mcnAbortClicked;
        QDataStream mdsIn;
        QElapsedTimer metTaken;
        QFile mfileRDF;
        RDF* mpRDF;
        char* mpcBuffer;
        QTimer* mptmrUpload;
        Ui::ImportRDF* mpui;
        quint64 muint64Block, muint64Total;
        uint muintDatasetID;
    
    public:
        explicit ImportRDF(QWidget* pParent = nullptr);
        ~ImportRDF();
    
        //Delete copy/move so additional instances can't be created/moved
        ImportRDF(const ImportRDF&) = delete;
        ImportRDF& operator=(const ImportRDF&) = delete;
        ImportRDF(ImportRDF&&) = delete;
        ImportRDF& operator=(ImportRDF&&) = delete;
    
        void closeDialog();
        static ImportRDF* pInstance() { return ImportRDF::mspInstance; }
        bool startImport(const QString& crstrFilename, const quint64 cuint64Size);
        long lngBScans();
        void setDatasetId(uint uintDatasetID) { muintDatasetID = uintDatasetID; }
        void updateElapsedTime();
    
    signals:
        void importComplete();
    
    public slots:
        void dbError(const QSqlError& crErr);
    };
    
    #endif // IMPORTRDF_H
    

    import.cpp

    /**
     * File:
     *  importrdf.cpp
     *
     * Notes:
     *  This file contains the implementation of the ImportRDF class.
     *
     * History:
     *  17/05/2021 Written by Simon Platten
     */
    #include "importrdf.h"
    #include "ui_importRDF.h"
    #include "trainer.h"
    //Static initialisation
    //UDP can send up to 65536 (64K) in a single packet, however we
    //need to allow for the format of how the data is being sent.
    //It will be repackaged as a hex string which means two hex nibbles
    //1 hex character for each nibble which means allowing for the
    //packet overhead and nibble conversion that it will be considerable
    //less.
    //65536 - 256 (message overhead) = Available chunk payload
    //Binary data is sent as ASCII nibbles so divide by 2
    const quint16 ImportRDF::mscuint16BlockSize         = (((65536 - 256) / 2));
    const quint16 ImportRDF::mscuint16UploadInterval    = 10;
    ImportRDF* ImportRDF::mspInstance                   = nullptr;
    /**
     * @brief ImportRDF::ImportRDF
     * @param pParent   Pointer to parent
     */
    ImportRDF::ImportRDF(QWidget* pParent) : QMainWindow(pParent),
                                             mdsIn(&mfileRDF),
                                             mpRDF(nullptr),
                                             mpui(new Ui::ImportRDF),
                                             mptmrUpload(nullptr),
                                             mpcBuffer(nullptr),
                                             muint64Block(0),
                                             muint64Total(0)
    {
        ImportRDF::mspInstance = this;
        mdsIn.setVersion(QDataStream::Qt_DefaultCompiledVersion);
        setWindowFlags(Qt::FramelessWindowHint);
        mpui->setupUi(this);
        mcnAbortClicked = QObject::connect(mpui->pbtnAbort, &QPushButton::clicked,
            [this]() {
        //Clean up database removing any incomplete imports
                QSqlQuery queryCleanup;
                queryCleanup.prepare("CALL deleteIncompleteDatasets();");
                Trainer::queryDB(queryCleanup);
                emit importComplete();
        //Close import dialog
                closeDialog();
            }
        );
        //Allocate enough memory for a single block
        mpcBuffer = new char[ImportRDF::mscuint16BlockSize];
    }
    /**
     * @brief ImportRDF::~ImportRDF
     */
    ImportRDF::~ImportRDF()
    {
        closeDialog();
        QObject::disconnect(mcnAbortClicked);
    
        if ( mpRDF != nullptr )
        {
            mpRDF->deleteLater();
        }
        delete mpcBuffer;
    }
    /**
     * @brief ImportRDF::closeDialog
     */
    void ImportRDF::closeDialog()
    {
        if ( mfileRDF.isOpen() == true )
        {
            mfileRDF.close();
        }
        //If a timer was created make sure it is stopped and deleted
        if ( mptmrUpload != nullptr )
        {
            mptmrUpload->stop();
            mptmrUpload->deleteLater();
            mptmrUpload = nullptr;
        }
        close();
    }
    /**
     * @brief ImportRDF::dbError
     * @param crErr     Constant reference to error
     */
    void ImportRDF::dbError(const QSqlError& crErr)
    {
        closeDialog();
        Q_UNUSED(crErr);
    }
    /**
     * @brief ImportRDF::lngBScans
     * @return Number of BScans in RDF or 0 if not ready
     */
    long ImportRDF::lngBScans()
    {
        if ( mpRDF != nullptr ) {
            return mpRDF->lngBScans();
        }
        return 0;
    }
    /**
     * @brief ImportRDF::startImport
     * @param crstrFilename     Constant reference to file name and path
     * @param cint64Size        Constant size of file to import
     * @return true if file is valid and import can go ahead else false
     */
    bool ImportRDF::startImport(const QString& crstrFilename,
                                const quint64 cuint64Size)
    {
        static QString sstrAbort(ImportRDF::tr("&Abort"));
        static QString sstrImportComplete(ImportRDF::tr("&Import complete"));
        if ( isVisible() == true || mptmrUpload != nullptr )
        {
        //Import dialog already visible or upload timer already exits, do nothing!
            return true;
        }    
        quint64 uint64BlockSize(static_cast<quint64>(ImportRDF::mscuint16BlockSize));
        muint64Total = cuint64Size / uint64BlockSize;
        if ( fmod(cuint64Size, uint64BlockSize) != 0 )
        {
            muint64Total++;
        }
        if ( muint64Total == 0 )
        {
        //Nothing to do, abort!
            return false;
        }
        //Populate controls
        QString strFilename(SckServer::removePath(crstrFilename));
        mpui->plblFilename->setText(strFilename);
        mpui->plblFilesize->setText(QString::number(cuint64Size));
        mpui->plblBScans->setText(QString::number(0));
        mpui->plblBlock->setText(QString::number(muint64Block));
        mpui->plblTotalBlocks->setText(QString::number(muint64Total));
        mpui->plblElapsed->setText(SckServer::mscszEmpty);
        mpui->plblRead->setText("0");
        mpui->pgbrStatus->setMinimum(0);
        mpui->pgbrStatus->setMaximum(muint64Total);
        //Reset block count
        muint64Block = 0;
        mpui->pgbrStatus->setValue(muint64Block);
        //Hide controls that aren't require yet
        mpui->plblChunksizeTxt->hide();
        mpui->plblRead->hide();
        mpui->pgbrStatus->hide();
        //Ensure the button text is set-back to "Abort"
        mpui->pbtnAbort->setText(sstrAbort);
        //Start the elapsed time taken
        metTaken.start();
        //Show the form
        show();
        if ( mpRDF == nullptr )
        {
        //Add entry to audit log
            QString strAudit(QString("Reading: %1 to determine BScans").arg(strFilename));
            QSqlQuery queryAuditEntry;
            queryAuditEntry.prepare("CALL addAuditEntry(?);");
            queryAuditEntry.addBindValue(strAudit);
            Trainer::queryDB(queryAuditEntry);
        //Create instance of RDF helper
            mpRDF = new RDF(crstrFilename.toLatin1().data());
        }
        if ( mpRDF == nullptr )
        {
        //Shouldn't get here!
            return false;
        }
        QObject::connect(mpRDF, &RDF::BScansUpdate,
            [this](const long clngBScans)
            {
                mpui->plblBScans->setText(QString::number(clngBScans));
                updateElapsedTime();
            }
        );
        QObject::connect(mpRDF, &RDF::complete,
            [this, crstrFilename, cuint64Size](const long clngBScans)
            {
        //Is the file ok?
                QString strLastError;
                if ( mpRDF->eLastError(&strLastError) != RDF_file_ok )
                {
                    QString strError(QString("Error: '%1' with RDF file: %2")
                                     .arg(strLastError).arg(crstrFilename));
                    Trainer::logError(strError.toLatin1().data());
                    return;
                }
        //Open the file for processing
                mfileRDF.setFileName(crstrFilename);
                if ( mfileRDF.open(QFile::ReadOnly) != true )
                {
                    QString strError(QString("Cannot open file: %1").arg(crstrFilename));
                    Trainer::logError(strError.toLatin1().data());
                    return;
                }
                QString strFilename(SckServer::removePath(crstrFilename));
                mpui->plblBScans->setText(QString::number(clngBScans));
        //Add entry to audit log
                QString strAudit(QString("Import started of: %1").arg(strFilename));
                QSqlQuery queryAuditEntry;
                queryAuditEntry.prepare("CALL addAuditEntry(?);");
                queryAuditEntry.addBindValue(strAudit);
                Trainer::queryDB(queryAuditEntry);
        //Create timer to perform upload
                mptmrUpload = new QTimer(this);
                QObject::connect(mptmrUpload, &QTimer::timeout,
                    [this, crstrFilename, strFilename, cuint64Size]()
                    {
                        if ( muint64Block < muint64Total )
                        {
        //Read a block of data
                            int intRead = mdsIn.readRawData(mpcBuffer, ImportRDF::mscuint16BlockSize);
                            if ( !(intRead > 0) )
                            {
                                return;
                            }
                            mpui->plblRead->setText(QString::number(intRead));
        //Transfer the buffer to the JSON array
                            QByteArray bytaryChunk;
                            for( int i=0; i<intRead; i++ )
                            {
                                bytaryChunk.append(mpcBuffer[i]);
                            }
                            quint8 uint8Checksum = SckServer::uint8CalcChecksum(mpcBuffer, intRead);
        //Write block to database
                            QSqlQuery queryBlock;
                            queryBlock.prepare("SELECT addBlock(?,?,?,?,?);");
                            queryBlock.addBindValue(muintDatasetID);
                            queryBlock.addBindValue(strFilename);
                            queryBlock.addBindValue(muint64Block);
                            queryBlock.addBindValue(bytaryChunk, QSql::Binary);
                            queryBlock.addBindValue(uint8Checksum);
                            if ( Trainer::queryDB(queryBlock) == true )
                            {
        //Increment block counter and update progress bar
                                mpui->pgbrStatus->setValue(++muint64Block);
                                mpui->plblBlock->setText(QString::number(muint64Block));
        //Show elapsed time
                                updateElapsedTime();
                            }
                        }
                        else
                        {
        //Update the number of chunks/blocks in the dataset RDF file
                            bool blnComplete(muint64Block == muint64Total);
                            QSqlQuery queryChunks;
                            queryChunks.prepare("CALL updateChunks(?,?,?,?);");
                            queryChunks.addBindValue(crstrFilename);
                            queryChunks.addBindValue(muint64Block);
                            queryChunks.addBindValue(cuint64Size);
                            queryChunks.addBindValue(((blnComplete == true) ? 1 : 0));
                            Trainer::queryDB(queryChunks);
        //Add entry to audit log
                            QString strAudit(QString("%1 of: %2").arg(sstrImportComplete)
                                                                 .arg(strFilename));
                            QSqlQuery queryAudit;
                            queryAudit.prepare("CALL addAuditEntry(?);");
                            queryAudit.addBindValue(strAudit);
                            Trainer::queryDB(queryAudit);
        //Change the abort button text
                            mpui->pbtnAbort->setText(sstrImportComplete);
        //Stop timer
                            mptmrUpload->stop();
                        }
                    }
                );
                mptmrUpload->start(ImportRDF::mscuint16UploadInterval);
        //Add stage audit entry
                queryAuditEntry.prepare("CALL addAuditEntry(?);");
                queryAuditEntry.addBindValue(QString("%1: %2 %3 %4")
                                                .arg(tr("BScans"))
                                                .arg(mpui->plblBScans->text())
                                                .arg(tr("Time taken"))
                                                .arg(mpui->plblElapsed->text()));
                Trainer::queryDB(queryAuditEntry);
        //Make sure the progress bar is visible
                mpui->plblChunksizeTxt->show();
                mpui->plblRead->show();
                mpui->pgbrStatus->show();
            }
        );
        return true;
    }
    /**
     * @brief ImportRDF::updateElapsedTime
     */
    void ImportRDF::updateElapsedTime()
    {
        static const quint64 scuint64MSinSec   = 1 * 1000;
        static const quint64 scuint64MSinMin   = scuint64MSinSec * 60;
        static const quint64 scuint64MSinHr    = scuint64MSinMin * 60;
        qint64 int64Hours, int64Mins, int64Secs;
        qint64 int64MS(metTaken.elapsed());
        int64Hours = int64MS / scuint64MSinHr;
        int64MS -= int64Hours * scuint64MSinHr;
        int64Mins = int64MS / scuint64MSinMin;
        int64MS -= int64Mins * scuint64MSinMin;
        int64Secs = int64MS / scuint64MSinSec;
        int64MS -= int64Secs * scuint64MSinSec;
        QString strHHMMSSZZZ = QString("%1:%2:%3.%4")
                    .arg(int64Hours, 2, 10, QLatin1Char('0'))
                    .arg(int64Mins, 2, 10, QLatin1Char('0'))
                    .arg(int64Secs, 2, 10, QLatin1Char('0'))
                    .arg(int64MS, 3, 10, QLatin1Char('0'));
        mpui->plblElapsed->setText(strHHMMSSZZZ);
    }
    


  • @jsulm , thank you, I haven't seen this, how do I do that?

    NVM, sorted, I added to the styleSheet in the UI:

    QMainWindow{border:8px solid black;}
    

  • Lifetime Qt Champion

    @SPlatten said in QMainWindow, no title, border:

    how do I implement a border on a window that has no title?

    Can't you simply add a QFrame to your window?



  • @jsulm , thank you, I haven't seen this, how do I do that?

    NVM, sorted, I added to the styleSheet in the UI:

    QMainWindow{border:8px solid black;}
    

  • Lifetime Qt Champion

    @SPlatten It's a widget, so simply add it to your window like any other widget and add it to the layout, so it consumes whole space. Then put all other widgets inside the frame.


Log in to reply