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. Set vertical tab close button issue
Forum Updated to NodeBB v4.3 + New Features

Set vertical tab close button issue

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 2 Posters 873 Views 1 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.
  • Cobra91151C Offline
    Cobra91151C Offline
    Cobra91151
    wrote on last edited by Cobra91151
    #1

    Hello!

    I want to change the default tab widget close button and set my icon instead. The problem is that it draws the icon on the text.

    Code:

    void AppTabBar::paintEvent(QPaintEvent *event)
    {
        QStylePainter painter(this);
        QStyleOptionTab opt;
    
        for (int i = 0; i < this->count(); i++) {
            initStyleOption(&opt, i);
            opt.text = painter.fontMetrics().elidedText(opt.text, Qt::ElideRight, 70);
            painter.drawControl(QStyle::CE_TabBarTabShape, opt);
            painter.save();
            QSize s = opt.rect.size();
    
            if (tabPos != AppTabPosition::Top && tabPos != AppTabPosition::Bottom) {
                s.transpose();
            }
    
            QRect r(QPoint(), s);
            r.moveCenter(opt.rect.center());
            opt.rect = r;
    
            QPoint c = tabRect(i).center();
            painter.translate(c);
    
            if (tabPos == AppTabPosition::Left) {
                painter.rotate(90);
            } else if (tabPos == AppTabPosition::Right) {
                painter.rotate(270); //90 - left pos, 270 - right pos
            }
    
            painter.translate(-c);
            painter.drawControl(QStyle::CE_TabBarTabLabel, opt);
            painter.restore();
        }
    
        QWidget::paintEvent(event);
    }
    
    
    void AppTabStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
    {
        if (element == PE_IndicatorTabClose) {
            int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize);
            QIcon::Mode mode = option->state & State_Enabled ? (option->state & State_Raised ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
    
            if (!(option->state & State_Raised) && !(option->state & State_Sunken) && !(option->state & QStyle::State_Selected)) {
                mode = QIcon::Disabled;
            }
    
            QIcon::State state = option->state & State_Sunken ? QIcon::On : QIcon::Off;
            QPixmap pixmap = QIcon(":/Icons/cross_icon.png").pixmap(size, mode, state);
            proxy()->drawItemPixmap(painter, option->rect, Qt::AlignRight, pixmap);
        } else {
            QProxyStyle::drawPrimitive(element, option, painter, widget);
        }
    }
    

    Screenshot:
    2021-05-13_200839.png

    Any ideas how to draw it to the right? Thank you.

    1 Reply Last reply
    0
    • Cobra91151C Offline
      Cobra91151C Offline
      Cobra91151
      wrote on last edited by
      #10

      Hello!

      Finally! I have fixed the issue with vertical tab close button position.

      Code:

      if (tabPos != AppTabPosition::Top && tabPos != AppTabPosition::Bottom) {
          s.transpose();
      
          if (this->tabsClosable()) { // check if tab is closable
              QRect optRect = opt.rect;
              optRect.setX(90); // set X pos of close button
              optRect.setY(optRect.y() + 8); // calcs the Y pos of close button
              optRect.setSize(QSize(12, 12));
              this->tabButton(i, QTabBar::RightSide)->setGeometry(optRect);
         }
      }
      

      Here I do not change the default opt.rect but instead I copy it to new QRect. Then I change the size and position of optRect and finally set geometry to tabButtton .

      Screenshot:

      alt text

      The issue is resolved.

      1 Reply Last reply
      0
      • Cobra91151C Offline
        Cobra91151C Offline
        Cobra91151
        wrote on last edited by
        #2

        I think I know what the problem is. I will reply soon.

        1 Reply Last reply
        0
        • Cobra91151C Offline
          Cobra91151C Offline
          Cobra91151
          wrote on last edited by Cobra91151
          #3

          Nope, my solution does not work. It draws 2 close buttons, then I hide the first one and display mine. Now, the problem is when clicking on X it does nothing.

          if (tabPos != AppTabPosition::Top && tabPos != AppTabPosition::Bottom) {
              s.transpose();
          
              if (this->tabsClosable()) { // check if tab is closable
                  opt.rect.setX(90); // set X pos of close button
                  this->tabButton(i, QTabBar::RightSide)->hide(); // hide the default close button
                  painter.drawPrimitive(QStyle::PE_IndicatorTabClose, opt); //draw new close button
                  opt.rect.setX(0); // set X pos to default
              }
          }
          

          How to connect the signal to a primitive type? Or is there any better solution to display the custom close tab icon. Thank you.

          1 Reply Last reply
          0
          • Cobra91151C Offline
            Cobra91151C Offline
            Cobra91151
            wrote on last edited by
            #4

            I think, the easiest way is to change the QRect in the drawPrimitive method but when I set for example X coordinate to 90, then my close icon becomes invisible.

            Code:

            void AppTabBarStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
            {
                if (element == PE_IndicatorTabClose) {
                    int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize);
                    QIcon::Mode mode = option->state & State_Enabled ? (option->state & State_Raised ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
            
                    if (!(option->state & State_Raised) && !(option->state & State_Sunken) && !(option->state & QStyle::State_Selected)) {
                        mode = QIcon::Disabled;
                    }
            
                    QIcon::State state = option->state & State_Sunken ? QIcon::On : QIcon::Off;
                    QPixmap pixmap = QIcon(":/Icon/red_cross_icon.png").pixmap(size, mode, state);
                    qDebug() << "Size: " << option->rect.size() << " | x:" << option->rect.x() << " | y:" << option->rect.y();
                    QRect testRect;
                    testRect.setX(90);
                    testRect.setY(5);
                    testRect.setSize(option->rect.size());
                    proxy()->drawItemPixmap(painter, testRect, Qt::AlignRight, pixmap);
                } else {
                    QProxyStyle::drawPrimitive(element, option, painter, widget);
                }
            }
            

            Any ideas how to override the default tab bar button? Thank you.

            SGaistS 1 Reply Last reply
            0
            • Cobra91151C Offline
              Cobra91151C Offline
              Cobra91151
              wrote on last edited by Cobra91151
              #5

              I have set setTabsClosable(false);, then created the TabBarLabel class and set it to setTabButton method. It closes the tabs but the issue with overlapping the tab text still exists:

              Screenshot:
              vertical_tabs_issue_example.gif

              It is a lot of code, so I have created and uploaded to Mega the test example to illustrate this issue. Here is my test example: TabExample.zip (6kb)

              Any ideas how to change position of tab bar close button? Thank you.

              1 Reply Last reply
              0
              • Cobra91151C Cobra91151

                I think, the easiest way is to change the QRect in the drawPrimitive method but when I set for example X coordinate to 90, then my close icon becomes invisible.

                Code:

                void AppTabBarStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
                {
                    if (element == PE_IndicatorTabClose) {
                        int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize);
                        QIcon::Mode mode = option->state & State_Enabled ? (option->state & State_Raised ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
                
                        if (!(option->state & State_Raised) && !(option->state & State_Sunken) && !(option->state & QStyle::State_Selected)) {
                            mode = QIcon::Disabled;
                        }
                
                        QIcon::State state = option->state & State_Sunken ? QIcon::On : QIcon::Off;
                        QPixmap pixmap = QIcon(":/Icon/red_cross_icon.png").pixmap(size, mode, state);
                        qDebug() << "Size: " << option->rect.size() << " | x:" << option->rect.x() << " | y:" << option->rect.y();
                        QRect testRect;
                        testRect.setX(90);
                        testRect.setY(5);
                        testRect.setSize(option->rect.size());
                        proxy()->drawItemPixmap(painter, testRect, Qt::AlignRight, pixmap);
                    } else {
                        QProxyStyle::drawPrimitive(element, option, painter, widget);
                    }
                }
                

                Any ideas how to override the default tab bar button? Thank you.

                SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #6

                Hi,
                @Cobra91151 said in Set vertical tab close button issue:

                testRect.setX(90);
                testRect.setY(5);
                testRect.setSize(option->rect.size());

                What are the rect values ?
                I would say that you are currently drawing in the wrong coordinate system.

                To get started, I would either get the code from the base model or one of the style examples in order to go from a working state.

                Interested in AI ? www.idiap.ch
                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                Cobra91151C 2 Replies Last reply
                0
                • SGaistS SGaist

                  Hi,
                  @Cobra91151 said in Set vertical tab close button issue:

                  testRect.setX(90);
                  testRect.setY(5);
                  testRect.setSize(option->rect.size());

                  What are the rect values ?
                  I would say that you are currently drawing in the wrong coordinate system.

                  To get started, I would either get the code from the base model or one of the style examples in order to go from a working state.

                  Cobra91151C Offline
                  Cobra91151C Offline
                  Cobra91151
                  wrote on last edited by Cobra91151
                  #7

                  @SGaist

                  Hello!

                  These are just test values. I no longer use void AppTabBarStyle::drawPrimitive to draw the X icon. Now, I use the TabBarLabel which inherits from QLabel. I will post the code for TabBarLabel soon.

                  1 Reply Last reply
                  0
                  • SGaistS SGaist

                    Hi,
                    @Cobra91151 said in Set vertical tab close button issue:

                    testRect.setX(90);
                    testRect.setY(5);
                    testRect.setSize(option->rect.size());

                    What are the rect values ?
                    I would say that you are currently drawing in the wrong coordinate system.

                    To get started, I would either get the code from the base model or one of the style examples in order to go from a working state.

                    Cobra91151C Offline
                    Cobra91151C Offline
                    Cobra91151
                    wrote on last edited by
                    #8

                    @SGaist

                    So, here is my code below:

                    tabbarlable.h

                    #ifndef TABBARLABEL_H
                    #define TABBARLABEL_H
                    
                    #include <QLabel>
                    #include <QObject>
                    #include <QPaintEvent>
                    #include <QMouseEvent>
                    #include "apptabbar.h"
                    #include <QDebug>
                    
                    class TabBarLabel : public QLabel
                    {
                        Q_OBJECT
                    public:
                        TabBarLabel(AppTabBar *parent, QPixmap image);
                        ~TabBarLabel();
                    
                    private:
                        int tabIndex() const;
                    
                    protected:
                        void mousePressEvent(QMouseEvent *event);
                    
                    private:
                        AppTabBar *tabBar;
                    };
                    
                    #endif // TABBARLABEL_H
                    

                    tabbarlabel.cpp

                    #include "tabbarlabel.h"
                    
                    TabBarLabel::TabBarLabel(AppTabBar *parent, QPixmap image) : QLabel(parent),
                        tabBar(parent)
                    {
                        this->setPixmap(image);
                        this->setScaledContents(true);
                        this->setStyleSheet("background: transparent;");
                        this->setToolTip(QObject::tr("Close"));
                    }
                    
                    void TabBarLabel::mousePressEvent(QMouseEvent *event)
                    {
                        qDebug() << "Clicked...";
                        QMetaObject::invokeMethod(tabBar, "tabCloseRequested", Qt::DirectConnection, Q_ARG(int, this->tabIndex()));
                        QLabel::mousePressEvent(event);
                    }
                    
                    int TabBarLabel::tabIndex() const
                    {
                        for (int i = 0; i < tabBar->count(); i++) {
                            if (tabBar->tabButton(i, QTabBar::RightSide) == this) {
                                return i;
                            }
                        }
                    
                        return -1;
                    }
                    
                    TabBarLabel::~TabBarLabel()
                    {
                    
                    }
                    

                    testwidget.cpp

                    TestWidget::TestWidget(QWidget *parent)
                        : QWidget(parent)
                    {
                        setMinimumSize(900, 560);
                        AppTabControl *tabControl = new AppTabControl(this, 30, 115);
                        tabControl->setTabsClosable(false);
                        connect(tabControl->tabBar(), &AppTabBar::tabCloseRequested, this, [this, tabControl](int tabIndex) {
                            tabControl->removeTab(tabIndex);
                        });
                        this->setStyleSheet("QTabBar::tab {color: #000000; font-weight: bold; font-size: 10px; font-family: Gotham, Helvetica Neue, Helvetica, Arial, sans-serif;} "
                                            "QTabBar::tab:selected {background-color: #FA9944; color: #000000; border-top: 1px solid #FA9944;} "
                                            "QTabBar::tab:hover {color: #000000; border-top: 1px solid #FA9944; background-color: #FFFFFF;}");
                        AppTabBar *tabBar1 = new AppTabBar(tabControl);
                        TabBarLabel *closeTab2Label = new TabBarLabel(reinterpret_cast<AppTabBar*>(tabControl->tabBar()), QIcon(":/Icons/close_tab_icon.png").pixmap(12, 12));
                        TabBarLabel *closeTab3Label = new TabBarLabel(reinterpret_cast<AppTabBar*>(tabControl->tabBar()), QIcon(":/Icons/close_tab_icon.png").pixmap(12, 12));
                        AppTabBar *tabBar2 = new AppTabBar(tabControl);
                        AppTabBar *tabBar3 = new AppTabBar(tabControl);
                        tabControl->addTab(tabBar1, "Tab1");
                        int tab2Index = tabControl->addTab(tabBar2, "Tab2");
                        int tab3Index = tabControl->addTab(tabBar3, "Tab3");
                        tabControl->tabBar()->setTabButton(tab2Index, QTabBar::RightSide, closeTab2Label);
                        tabControl->tabBar()->setTabButton(tab3Index, QTabBar::RightSide, closeTab3Label);
                        QHBoxLayout *mainLayout = new QHBoxLayout();
                        mainLayout->setContentsMargins(QMargins());
                        mainLayout->addWidget(tabControl);
                        setLayout(mainLayout);
                    }
                    

                    The actual vertical tab bar draws here:

                    void AppTabBar::paintEvent(QPaintEvent *event)
                    {
                        QStylePainter painter(this);
                        QStyleOptionTab opt;
                    
                        for (int i = 0; i < this->count(); i++) {
                            initStyleOption(&opt, i);
                            painter.drawControl(QStyle::CE_TabBarTabShape, opt);
                            painter.save();
                    
                            QSize s = opt.rect.size();
                            s.transpose();
                            QRect r(QPoint(), s);
                            r.moveCenter(opt.rect.center());
                            opt.rect = r;
                    
                            QPoint c = tabRect(i).center();
                            painter.translate(c);
                            painter.rotate(90);
                    
                            painter.translate(-c);
                            painter.drawControl(QStyle::CE_TabBarTabLabel, opt);
                            painter.restore();
                        }
                    
                        QWidget::paintEvent(event);
                    }
                    

                    I have checked the X and Y for TabBarLabel:
                    qDebug() << "x: " << tabControl->tabBar()->tabButton(tab2Index, QTabBar::RightSide)->pos().x() << " | y:" << tabControl->tabBar()->tabButton(tab2Index, QTabBar::RightSide)->pos().y(); it returns x: 52 | y: 39

                    This issue only happens for tab position - QTabWidget::West and QTabWidget::East. Any ideas how to fix it? Thank you.

                    1 Reply Last reply
                    0
                    • Cobra91151C Offline
                      Cobra91151C Offline
                      Cobra91151
                      wrote on last edited by
                      #9

                      I think the following: s.transpose(); swaps the width and height around in order to display the vertical tabs correctly. But the tab bar close button does not know about it and wrongly calculates the position. I need to reimplement the method where tab bar close button makes the calculation/drawing on a tab to fix this issue. Now, the question is what is the name of such method. I think it could be one of this two methods:

                      1. AppTabBar::paintEvent
                      2. TabBarLabel::paintEvent
                      
                      1 Reply Last reply
                      0
                      • Cobra91151C Offline
                        Cobra91151C Offline
                        Cobra91151
                        wrote on last edited by
                        #10

                        Hello!

                        Finally! I have fixed the issue with vertical tab close button position.

                        Code:

                        if (tabPos != AppTabPosition::Top && tabPos != AppTabPosition::Bottom) {
                            s.transpose();
                        
                            if (this->tabsClosable()) { // check if tab is closable
                                QRect optRect = opt.rect;
                                optRect.setX(90); // set X pos of close button
                                optRect.setY(optRect.y() + 8); // calcs the Y pos of close button
                                optRect.setSize(QSize(12, 12));
                                this->tabButton(i, QTabBar::RightSide)->setGeometry(optRect);
                           }
                        }
                        

                        Here I do not change the default opt.rect but instead I copy it to new QRect. Then I change the size and position of optRect and finally set geometry to tabButtton .

                        Screenshot:

                        alt text

                        The issue is resolved.

                        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