Qt 5.15.2自定义ComboBox预选索引>10时条目下移问题求助
自定义ComboBox在Qt 5.15.2中的显示异常问题排查与解决
问题现象
开发带删除按钮的自定义ComboBox(已剔除无关代码),在mainwindow.cpp中创建并预选条目时:
- 索引小于10时,下拉列表显示正常;
- Windows系统Qt 5.15.2环境下,索引大于10时,条目标签随索引值下移,但工具提示(tooltip)显示正常;
- Qt 6.6.3环境下无此问题。
补充说明
Qt 5.15.2会按需显示右侧滚动条,但下拉列表始终从第一个元素(1111)开始显示,即使该元素不应位于下拉列表顶部。第二张截图为滚动至第一个元素后截取:
- 预选索引1:条目标签显示正常,无偏移
- 预选索引11:条目标签向下偏移两行
代码实现
main.cpp
#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.h
#include <QMainWindow> #include "comboboxwithremovebutton.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; ComboBoxWithRemoveButton* cb; QWidget *window; };
mainwindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QLayout> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); cb = new ComboBoxWithRemoveButton(this); QHBoxLayout *hlayout = new QHBoxLayout; hlayout->addWidget(cb); window = new QWidget(this); window->setLayout(hlayout); setCentralWidget(window); cb->setMinimumSize(310, 28); cb->addItems({"1111", "2222", "3333", "4444", "5555", "6666", "7777", "8888", "9999", "0000", "1111", "2222", "3333"}); cb->setCurrentIndex(11); } MainWindow::~MainWindow() { delete ui; }
comboboxwithremovebutton.h
#ifndef COMBOBOXWITHREMOVEBUTTON_H #define COMBOBOXWITHREMOVEBUTTON_H #include <QComboBox> #include <QHBoxLayout> #include <QLabel> #include <QListWidget> class ComboBoxWithRemoveButton; class ComboBoxWidget : public QWidget { Q_OBJECT public: ComboBoxWidget(QString text, ComboBoxWithRemoveButton *cb, QWidget* parent = 0); public: QHBoxLayout *horizontalLayout; QLabel *label; }; class ComboBoxWithRemoveButton : public QComboBox { Q_OBJECT public: ComboBoxWithRemoveButton(QWidget *parent = 0); void addItems(const QStringList &texts); private: QListWidget *listWidget; }; #endif // COMBOBOXWITHREMOVEBUTTON_H
comboboxwithremovebutton.cpp
#include "comboboxwithremovebutton.h" #include <QLabel> #include <QLineEdit> ComboBoxWithRemoveButton::ComboBoxWithRemoveButton(QWidget* parent) : QComboBox(parent) { listWidget = new QListWidget(this); setModel(listWidget->model()); setView(listWidget); } void ComboBoxWithRemoveButton::addItems(const QStringList &texts) { for(const QString& e : texts) { QListWidgetItem *listWidgetItem = new QListWidgetItem(listWidget); listWidgetItem->setToolTip(e); ComboBoxWidget *comboBoxWidget = new ComboBoxWidget(e, this); listWidgetItem->setSizeHint(comboBoxWidget->sizeHint()); listWidget->addItem(listWidgetItem); listWidget->setItemWidget(listWidgetItem, comboBoxWidget); view()->setCurrentIndex(model()->index(currentIndex(), 0)); } } ComboBoxWidget::ComboBoxWidget(QString text, ComboBoxWithRemoveButton *cb, QWidget* parent) : QWidget(parent) { horizontalLayout = new QHBoxLayout(); label = new QLabel(text); horizontalLayout->addWidget(label); setLayout(horizontalLayout); }
问题排查与解决办法
自身代码问题排查
- 循环内错误的视图索引设置:
addItems方法中,每次添加条目后调用view()->setCurrentIndex(model()->index(currentIndex(), 0)),但currentIndex()在循环过程中未更新,始终为初始值,反复重置视图索引会干扰Qt 5.15.2的内部布局计算。 - 自定义Widget布局边距:
ComboBoxWidget的布局未设置边距,Qt 5.15.2对自定义Item Widget的布局计算更敏感,额外边距可能导致偏移。 - QListWidget与ComboBox的绑定方式:直接复用QListWidget的model和view,在Qt 5中存在兼容隐患,Qt 6已修复此类问题。
Qt 5.15.2适配方案
方案1:修正addItems方法
移除循环内的视图索引设置,统一在条目添加完成后设置当前索引:
void ComboBoxWithRemoveButton::addItems(const QStringList &texts) { for(const QString& e : texts) { QListWidgetItem *listWidgetItem = new QListWidgetItem(listWidget); listWidgetItem->setToolTip(e); ComboBoxWidget *comboBoxWidget = new ComboBoxWidget(e, this); listWidgetItem->setSizeHint(comboBoxWidget->sizeHint()); listWidget->addItem(listWidgetItem); listWidget->setItemWidget(listWidgetItem, comboBoxWidget); // 移除该行错误调用 } }
方案2:优化自定义Widget布局
为ComboBoxWidget的布局设置0边距,避免额外间距影响:
ComboBoxWidget::ComboBoxWidget(QString text, ComboBoxWithRemoveButton *cb, QWidget* parent) : QWidget(parent) { horizontalLayout = new QHBoxLayout(this); horizontalLayout->setContentsMargins(0, 0, 0, 0); // 添加边距设置 label = new QLabel(text); horizontalLayout->addWidget(label); setLayout(horizontalLayout); }
方案3:改用标准模型视图替代QListWidget
若前两种方案无效,可替换为QStandardItemModel+QListView的组合:
// comboboxwithremovebutton.cpp修改 ComboBoxWithRemoveButton::ComboBoxWithRemoveButton(QWidget* parent) : QComboBox(parent) { QStandardItemModel *model = new QStandardItemModel(this); QListView *view = new QListView(this); setModel(model); setView(view); } void ComboBoxWithRemoveButton::addItems(const QStringList &texts) { QStandardItemModel *model = qobject_cast<QStandardItemModel*>(this->model()); if (!model) return; for(const QString& e : texts) { QStandardItem *item = new QStandardItem(); item->setToolTip(e); ComboBoxWidget *comboBoxWidget = new ComboBoxWidget(e, this); item->setSizeHint(comboBoxWidget->sizeHint()); model->appendRow(item); view()->setIndexWidget(item->index(), comboBoxWidget); } }
内容的提问来源于stack exchange,提问作者robert
相关产品推荐
相关产品推荐

