gui.utils.dropdown_button
1# Copyright (C) 2026 David Vaquero <pepesan@gmail.com> 2# 3# This program is free software: you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation, either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <https://www.gnu.org/licenses/>. 15 16from PySide6.QtWidgets import QPushButton, QMenu 17from PySide6.QtCore import Signal 18 19 20class DropdownButton(QPushButton): 21 """ 22 Reemplaza QComboBox con la estética del selector de curso: 23 botón con flecha ▾ que abre un QMenu estilizado con el tema activo. 24 25 API compatible con QComboBox: 26 addItem(text, userData=None) 27 addItems(texts) 28 currentText() / currentData() / currentIndex() 29 setCurrentIndex(idx) / setCurrentText(text) 30 count() / itemData(idx) 31 Signal currentIndexChanged(int) 32 """ 33 34 currentIndexChanged = Signal(int) 35 36 def __init__(self, parent=None): 37 super().__init__(parent) 38 self.setObjectName('dropdown_btn') 39 self._items: list[tuple[str, object]] = [] 40 self._current: int = -1 41 self.clicked.connect(self._show_menu) 42 43 # ── Construcción de ítems ───────────────────────────────────────────────── 44 45 def addItem(self, text: str, userData=None) -> None: 46 self._items.append((text, userData)) 47 if self._current == -1: 48 self._apply(0, emit=False) 49 50 def addItems(self, texts) -> None: 51 for t in texts: 52 self.addItem(t) 53 54 # ── Consulta ────────────────────────────────────────────────────────────── 55 56 def currentText(self) -> str: 57 if 0 <= self._current < len(self._items): 58 return self._items[self._current][0] 59 return '' 60 61 def currentData(self): 62 if 0 <= self._current < len(self._items): 63 return self._items[self._current][1] 64 return None 65 66 def currentIndex(self) -> int: 67 return self._current 68 69 def count(self) -> int: 70 return len(self._items) 71 72 def itemData(self, idx: int): 73 if 0 <= idx < len(self._items): 74 return self._items[idx][1] 75 return None 76 77 # ── Selección ───────────────────────────────────────────────────────────── 78 79 def setCurrentIndex(self, idx: int) -> None: 80 if 0 <= idx < len(self._items): 81 self._apply(idx) 82 83 def setCurrentText(self, text: str) -> None: 84 for i, (label, _) in enumerate(self._items): 85 if label == text: 86 self._apply(i) 87 return 88 89 # ── Internos ────────────────────────────────────────────────────────────── 90 91 def _apply(self, idx: int, emit: bool = True) -> None: 92 if idx == self._current: 93 return 94 self._current = idx 95 self.setText(f'{self.currentText()} ▾') 96 if emit: 97 self.currentIndexChanged.emit(idx) 98 99 def _show_menu(self) -> None: 100 menu = QMenu(self) 101 for i, (label, _) in enumerate(self._items): 102 act = menu.addAction(label) 103 act.setData(i) 104 if i == self._current: 105 act.setCheckable(True) 106 act.setChecked(True) 107 chosen = menu.exec(self.mapToGlobal(self.rect().bottomLeft())) 108 if chosen is not None: 109 self._apply(chosen.data())
class
DropdownButton(PySide6.QtWidgets.QPushButton):
21class DropdownButton(QPushButton): 22 """ 23 Reemplaza QComboBox con la estética del selector de curso: 24 botón con flecha ▾ que abre un QMenu estilizado con el tema activo. 25 26 API compatible con QComboBox: 27 addItem(text, userData=None) 28 addItems(texts) 29 currentText() / currentData() / currentIndex() 30 setCurrentIndex(idx) / setCurrentText(text) 31 count() / itemData(idx) 32 Signal currentIndexChanged(int) 33 """ 34 35 currentIndexChanged = Signal(int) 36 37 def __init__(self, parent=None): 38 super().__init__(parent) 39 self.setObjectName('dropdown_btn') 40 self._items: list[tuple[str, object]] = [] 41 self._current: int = -1 42 self.clicked.connect(self._show_menu) 43 44 # ── Construcción de ítems ───────────────────────────────────────────────── 45 46 def addItem(self, text: str, userData=None) -> None: 47 self._items.append((text, userData)) 48 if self._current == -1: 49 self._apply(0, emit=False) 50 51 def addItems(self, texts) -> None: 52 for t in texts: 53 self.addItem(t) 54 55 # ── Consulta ────────────────────────────────────────────────────────────── 56 57 def currentText(self) -> str: 58 if 0 <= self._current < len(self._items): 59 return self._items[self._current][0] 60 return '' 61 62 def currentData(self): 63 if 0 <= self._current < len(self._items): 64 return self._items[self._current][1] 65 return None 66 67 def currentIndex(self) -> int: 68 return self._current 69 70 def count(self) -> int: 71 return len(self._items) 72 73 def itemData(self, idx: int): 74 if 0 <= idx < len(self._items): 75 return self._items[idx][1] 76 return None 77 78 # ── Selección ───────────────────────────────────────────────────────────── 79 80 def setCurrentIndex(self, idx: int) -> None: 81 if 0 <= idx < len(self._items): 82 self._apply(idx) 83 84 def setCurrentText(self, text: str) -> None: 85 for i, (label, _) in enumerate(self._items): 86 if label == text: 87 self._apply(i) 88 return 89 90 # ── Internos ────────────────────────────────────────────────────────────── 91 92 def _apply(self, idx: int, emit: bool = True) -> None: 93 if idx == self._current: 94 return 95 self._current = idx 96 self.setText(f'{self.currentText()} ▾') 97 if emit: 98 self.currentIndexChanged.emit(idx) 99 100 def _show_menu(self) -> None: 101 menu = QMenu(self) 102 for i, (label, _) in enumerate(self._items): 103 act = menu.addAction(label) 104 act.setData(i) 105 if i == self._current: 106 act.setCheckable(True) 107 act.setChecked(True) 108 chosen = menu.exec(self.mapToGlobal(self.rect().bottomLeft())) 109 if chosen is not None: 110 self._apply(chosen.data())
Reemplaza QComboBox con la estética del selector de curso: botón con flecha ▾ que abre un QMenu estilizado con el tema activo.
API compatible con QComboBox:
addItem(text, userData=None) addItems(texts) currentText() / currentData() / currentIndex() setCurrentIndex(idx) / setCurrentText(text) count() / itemData(idx) Signal currentIndexChanged(int)