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

Set vertical tab close button issue

Scheduled Pinned Locked Moved Solved General and Desktop
10 Posts 2 Posters 1.2k 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