Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
FREEDOM251

Freedom251 › Blog › PyQt6

PyQt6 QTabWidget Beside Other Widgets: Build a Balanced Layout Without Window Takeover

By Freedom251 Team · · 11 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Put the QTabWidget and every neighboring control in one top-level layout. Use a QHBoxLayout for a tab area beside a sidebar, a QVBoxLayout for tabs between a toolbar and status area, or nested layouts for a mixed design. Give each tab page its own layout before calling addTab(), then use stretch factors and size policies to decide which region absorbs extra space.

The tab widget is not a special full-window container. It is an ordinary widget containing a tab bar and a page area, so Qt can place it beside labels, buttons, forms, or child layouts just like any other widget.

As an Amazon Associate I earn from qualifying purchases.

The layout hierarchy that keeps QTabWidget under control

A reliable PyQt6 interface has a clear ownership tree:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. The main window or central QWidget owns exactly one top-level layout.
  2. That outer layout owns the QTabWidget and any neighboring widgets or sub-layouts.
  3. Each tab is backed by a separate page QWidget.
  4. Each page installs its own child layout before the page is passed to addTab().

Qt’s layout system calculates positions, minimum sizes, and resizing behavior for this tree. A tab page without a layout has no organized child geometry, while a page with a layout can report sensible size requirements as its contents change. The page layout does not replace the outer layout; the two solve different problems.

#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter | 4Pack Type C Female to A Male Cable Converter for Apple Duo 17 16 15 14 Plus,iWatch Watch 12 11 10,iPad 9 8 Air,Airpods 5 4
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.

Do not create one layout for the tabs and another unrelated layout for the sidebar on the same parent widget. A widget can have one installed top-level layout. If you need several regions, create child layouts and add them to the single outer layout with addLayout().

A complete side-by-side PyQt6 example

This example places expanding tabs on the left and a compact sidebar on the right. The tab pages are created and laid out before they are inserted.

import sys
from PyQt6.QtWidgets import (
    QApplication, QWidget, QTabWidget, QLabel, QPushButton,
    QVBoxLayout, QHBoxLayout
)


class Window(QWidget):
    def __init__(self):
        super().__init__()

        tabs = QTabWidget()

        first_page = QWidget()
        first_layout = QVBoxLayout(first_page)
        first_layout.addWidget(QLabel("First tab"))
        first_layout.addWidget(QPushButton("Action"))
        tabs.addTab(first_page, "First")

        second_page = QWidget()
        second_layout = QVBoxLayout(second_page)
        second_layout.addWidget(QLabel("Second tab"))
        tabs.addTab(second_page, "Second")

        sidebar = QVBoxLayout()
        sidebar.addWidget(QLabel("Sidebar"))
        sidebar.addWidget(QPushButton("Help"))
        sidebar.addStretch()

        outer = QHBoxLayout(self)
        outer.addWidget(tabs, 1)
        outer.addLayout(sidebar)

        self.setWindowTitle("Tabs beside other widgets")
        self.resize(800, 500)


app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec())

QHBoxLayout(self) installs the one top-level layout on the window. The call outer.addWidget(tabs, 1) adds the tab widget and gives it a positive stretch factor. The sidebar is a child QVBoxLayout, so outer.addLayout(sidebar) places that complete vertical region beside the tabs.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When the window grows horizontally, the tab region receives the surplus space while the sidebar remains close to its preferred width. Vertically, both regions follow the outer layout’s available height; the sidebar’s addStretch() keeps its controls at the top.

Choose the outer layout by the visual relationship

Use the layout direction to express how the regions should relate. The tab widget itself does not determine whether the interface is horizontal or vertical.

Arrangement Outer layout Typical children Space-allocation pattern
Tabs beside a sidebar QHBoxLayout Tab widget plus a sidebar layout or side widget Give the tabs a positive stretch; keep the sidebar at its preferred width
Toolbar above tabs QVBoxLayout Toolbar layout, tab widget, status area Give the tab widget a positive vertical stretch
Tabs beside a stacked control panel QHBoxLayout containing a child QVBoxLayout Tab widget plus a vertically arranged form or button column Stretch the tab region; let the child column manage its own spacing
Two control groups beside tabs QHBoxLayout with multiple child layouts Tab widget, filter layout, action layout Assign stretch factors according to the desired proportions

Side-by-side tabs and sidebar

The minimal pattern is:

outer = QHBoxLayout(self)
outer.addWidget(tabs, 1)
outer.addWidget(side_panel)

If the side panel contains several controls, use a child layout instead:

side_layout = QVBoxLayout()
side_layout.addWidget(QLabel("Filters"))
side_layout.addWidget(filter_edit)
side_layout.addWidget(apply_button)
side_layout.addStretch()

outer = QHBoxLayout(self)
outer.addWidget(tabs, 1)
outer.addLayout(side_layout)

addWidget() and addLayout() both add a region to the same row. The sidebar does not need a wrapper widget unless you need a background, border, independent margins, or a separate object to show and hide.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Rank #2
Sale
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter | USB C Dongle with 90W Max Power Delivery, 3×5Gbps USB A Data Ports, for MacBook, Dell, and More (Charger Not Included)
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Toolbar, tabs, and status area stacked vertically

For a conventional editor window, stack the regions:

toolbar_layout = QHBoxLayout()
toolbar_layout.addWidget(QPushButton("New"))
toolbar_layout.addWidget(QPushButton("Open"))
toolbar_layout.addStretch()

status_layout = QHBoxLayout()
status_layout.addWidget(QLabel("Ready"))
status_layout.addStretch()

outer = QVBoxLayout(self)
outer.addLayout(toolbar_layout)
outer.addWidget(tabs, 1)
outer.addLayout(status_layout)

The positive stretch on the tab widget makes it absorb extra vertical space. The toolbar and status row retain their preferred heights.

Mixed nested layouts

Nested layouts are the normal way to build a more complex interface. A layout can contain widgets and other layouts; each child layout then controls only its own region.

left_column = QVBoxLayout()
left_column.addWidget(QLabel("Project"))
left_column.addWidget(project_tree)
left_column.addWidget(QPushButton("Refresh"))

outer = QHBoxLayout(self)
outer.addLayout(left_column)
outer.addWidget(tabs, 1)

Here the project controls form one vertical column, while the tab widget receives the remaining horizontal space.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Stretch factors, size policies, and minimum sizes

A stretch factor is a relative share of extra space in the layout’s direction. In outer.addWidget(tabs, 1), the tab widget has a positive factor and therefore grows when the window has room. If two regions use factors 1 and 2, the second region receives roughly twice the extra space, subject to each widget’s minimum size and size policy.

outer.addWidget(navigation, 1)
outer.addWidget(tabs, 3)

This creates a 1:3 preference for surplus horizontal space, not a guarantee that the widgets will always be exactly 25% and 75%. Minimum sizes, maximum sizes, and policies can limit the result.

Setting stretch after construction

When the tab widget is already in a box layout, you can set a stretch factor by index:

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter | 85W Max PD, 2 USB 3.0 & 1 USBC Data Ports, SD/TF Card Reader, for Laptops/Mac and Other Type C Devices (Charger Not Included)
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
outer.addWidget(side_panel)
outer.addWidget(tabs)
outer.setStretchFactor(side_panel, 0)
outer.setStretchFactor(tabs, 1)

The index passed to setStretchFactor() is the index of the widget or layout in that box layout. Setting a positive factor on the region intended to expand is usually clearer than trying to force a fixed width on every neighbor.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When no positive stretch is present

If all stretch factors are zero, Qt uses the participating widgets’ size policies and their size hints to distribute available space. That can be perfectly appropriate for a row of controls, but it can also make a sidebar or tab area appear unexpectedly narrow. Add a positive stretch to the region that should absorb remaining space instead of relying on implicit policy decisions.

Check the neighbor before blaming QTabWidget

A tab area can look as if it has taken over when the neighboring widget has an unusually small minimum size, a restrictive maximum size, or a policy that refuses to expand. Inspect the side region as well as the tabs. A layout can only distribute the space allowed by all of its children.

Build every tab page with its own layout

QTabWidget manages a tab bar and a page area. Each tab points to a page QWidget; the page is where you place labels, forms, tables, and buttons.

page = QWidget()
page_layout = QVBoxLayout(page)
page_layout.addWidget(QLabel("Settings"))
page_layout.addWidget(settings_form)
tabs.addTab(page, "Settings")

Passing the page to QVBoxLayout(page) installs that layout immediately. You can also create the layout separately and call page.setLayout(page_layout). The important part is that the page has a layout before it is used as a tab.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why empty pages cause confusing sizing

An empty page has little content from which to derive a useful size hint. The resulting minimum-size calculation can be surprising, particularly when several empty pages are combined with a sidebar or other constrained controls. Give each page real content or at least an intentional layout containing the controls that will eventually appear.

If a page is deliberately empty, install its layout anyway:

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray | Data transfer & Fast charging for MacBook, iPhone 17/16/15, iPad, Samsung Galaxy, Apple Watch
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
empty_page = QWidget()
empty_layout = QVBoxLayout(empty_page)
empty_layout.addStretch()
tabs.addTab(empty_page, "Nothing yet")

The stretch makes the page’s intent explicit and gives you a place to add content later without changing the ownership structure.

Adding pages dynamically

When a user creates a new document or workspace, construct the page, install its layout, and then insert it:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
def add_workspace(self, name):
    page = QWidget()
    layout = QVBoxLayout(page)
    layout.addWidget(QLabel(f"Workspace: {name}"))
    self.tabs.addTab(page, name)
    self.tabs.setCurrentWidget(page)

Build the initial tab set before calling show() whenever possible. Adding tabs after the window is visible is supported, but it can trigger layout adjustment and visible flicker while Qt recalculates the page area.

Making controls inside tabs expand correctly

The outer layout controls how much space the tab widget receives. The page layout controls how that space is shared by the page’s children. To let a table, editor, or other main control grow, place it in the page layout with an appropriate stretch position and keep small controls in non-stretch positions.

page_layout = QVBoxLayout(page)
page_layout.addWidget(QLabel("Description"))
page_layout.addWidget(description_edit, 1)
page_layout.addWidget(QPushButton("Save"))

The editor receives the page’s extra vertical space while the label and button keep their preferred heights. For a horizontal form, use a QHBoxLayout or a form layout inside the page and give the field region the expansion it needs.

Remember the two levels of stretch: the outer layout decides how much room the entire tab widget gets; the page layout decides how the widgets inside the selected page use that room. Setting a stretch only inside the page cannot make the tab widget wider if the outer row gives it no surplus space.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Diagnose the “QTabWidget takes over the whole window” symptom

When the tabs appear to occupy everything, inspect the layout tree in this order.

Best Value
Sale
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display | 85W Max PD, 1 Powered USB-C 5Gbps & 2 Powered USB-A 3.0 5Gbps Data Ports, for MacBook Pro, MacBook Air, Dell and More (Black)
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Symptom Likely cause Correction
Sidebar is missing or appears below the window edge The sidebar was never added to the same top-level layout, or a second layout was created on the parent Install one outer layout and add the sidebar with addWidget() or addLayout()
Tabs consume nearly all horizontal space The tab widget has a positive stretch while the sidebar has a tiny minimum size Check the sidebar’s size policy and minimum size; use deliberate stretch factors
Page controls overlap or stay in a corner Children were placed on a page without installing a page layout Create a page layout before adding the page to the tab widget
Empty tabs resize unpredictably Pages have no content or layout from which to calculate a useful size hint Install a page layout and add the intended controls or a stretch
Window flickers when tabs are added Tabs are being constructed after the window is shown Build the initial tabs before show(); add later pages only when needed
Tab contents do not grow with the window The page layout or the outer layout gives no expanding region Use a page-level stretch for the main control and a positive outer stretch for the tab widget

Verify the parent has exactly one top-level layout

Look at the widget that owns the visible interface, not at the tab page. It should have one layout installed. If you need a toolbar, sidebar, or footer, represent each as a child layout or child widget in that one layout. Creating another top-level layout on the same parent can leave controls unmanaged or produce warnings.

Confirm the tab widget was added as a widget

Use outer.addWidget(tabs), not a second top-level layout around it. A QTabWidget is a QWidget, so it belongs in a layout through addWidget(). A sidebar made from a layout belongs through addLayout().

Inspect minimum and maximum constraints

Fixed widths and large minimum widths on a neighboring panel can force the tab region to consume the remainder or, at a small window size, leave no usable room for it. Remove accidental constraints or choose them intentionally. Also check that a control has not been given a maximum width that prevents it from participating in expansion.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Reusable patterns for common interfaces

Tabs with a fixed-width action rail

If the action rail should stay compact while the tabs expand, give the rail a sensible fixed or minimum width and the tab widget a positive stretch.

actions = QWidget()
actions_layout = QVBoxLayout(actions)
actions_layout.addWidget(QPushButton("Run"))
actions_layout.addWidget(QPushButton("Stop"))
actions_layout.addStretch()

actions.setMinimumWidth(140)
outer = QHBoxLayout(self)
outer.addWidget(tabs, 1)
outer.addWidget(actions)

Use a minimum width only when the rail genuinely needs it; otherwise its size hint and policy are less restrictive and adapt better to small windows.

Tabs between a navigation column and an inspector

navigation_layout = QVBoxLayout()
navigation_layout.addWidget(QLabel("Navigation"))
navigation_layout.addWidget(tree)
navigation_layout.addStretch()

inspector_layout = QVBoxLayout()
inspector_layout.addWidget(QLabel("Inspector"))
inspector_layout.addWidget(properties)

outer = QHBoxLayout(self)
outer.addLayout(navigation_layout)
outer.addWidget(tabs, 2)
outer.addLayout(inspector_layout, 1)

The factors express the intended relative share of surplus width: the tab region gets two parts and the inspector one. The navigation column has no positive factor, so its preferred width is preserved as far as the other constraints allow.

Tabs with a header row and footer

header = QHBoxLayout()
header.addWidget(QLabel("Project"))
header.addWidget(project_name)
header.addStretch()

footer = QHBoxLayout()
footer.addWidget(status_label)
footer.addStretch()
footer.addWidget(close_button)

outer = QVBoxLayout(self)
outer.addLayout(header)
outer.addWidget(tabs, 1)
outer.addLayout(footer)

This keeps the header and footer outside the tab pages, so they remain visible while the user switches tabs. Controls that belong only to one tab should instead be placed on that page.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A practical construction and resize checklist

  1. Create the main container widget and install one outer layout.
  2. Choose QHBoxLayout for side-by-side regions or QVBoxLayout for stacked regions.
  3. Create the QTabWidget as a child of the container.
  4. For each tab, create a page QWidget, install its layout, add the page controls, and call addTab(page, label).
  5. Create neighboring widgets or child layouts and add them to the same outer layout.
  6. Give the region that should absorb extra space a positive stretch factor.
  7. Check the neighboring widgets’ minimum sizes, maximum sizes, and size policies.
  8. Build the initial interface before show().
  9. Resize the window from its minimum practical size to a large size and verify both the outer regions and the selected page contents.

Testing at both extremes catches different errors. A layout that looks correct at 800 by 500 can still hide a sidebar when narrowed or leave a page editor fixed at a tiny height when enlarged.

How to decide between a widget wrapper and a child layout

Add a child layout directly when you only need arrangement. Wrap the region in a QWidget when the region needs its own visual identity or lifecycle: a background palette, a frame, a context menu, independent visibility, or a named object you will replace later.

side_panel = QWidget()
side_layout = QVBoxLayout(side_panel)
side_layout.addWidget(QLabel("Tools"))
side_layout.addWidget(tool_button)
side_layout.addStretch()

outer = QHBoxLayout(self)
outer.addWidget(tabs, 1)
outer.addWidget(side_panel)

The wrapper is still just one child of the outer layout. The tab widget does not need special treatment because it is a regular widget from the outer layout’s point of view.

Key principles to keep when the interface grows

  • Keep the outer layout responsible for regions, not for the individual controls inside every page.
  • Keep each page’s layout responsible for that page’s controls.
  • Use stretch factors to express preference for extra space rather than relying on accidental defaults.
  • Use nested layouts for structure; do not create competing top-level layouts on one parent.
  • Treat empty pages as incomplete layout trees and give them an intentional layout.
  • Construct the stable tab set before showing the window to avoid unnecessary visible rearrangement.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

PyQt6Python GUIQHBoxLayoutQt layoutsQTabWidgetQVBoxLayout

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.