开发过程中会遇到各种问题,本文旨在记录开发过程中遇到的问题,以及如何规避解决这样的问题。
问题描述感觉不是很清楚,直接看总结,可能更好一点。
场景
需要创建一个窗口,如下图,通过按键切换不同的界面,下方的五个像按钮一样的不能通过鼠标触发,只是显示功能,需要按下键盘上特定的按键主显示区域便会显示不同的界面,同时通过按下esc按键可以返回上一级界面。
在这样的需求下,我采用的是堆栈窗口,按下下方不同的按键,主显示区域会切换不同的堆栈子窗口。
遇到问题
当按下其中一个下方的标签文本对应的特定按键后,切换另一个窗口在主显示区域显示,但是本该显示的窗口没有显示出来。FaultFindContainerWindow类是一个包含堆栈窗口的容器类。
原本的代码是这么写的。
void MainWindow::faultFind()
{
if(m_pFaultFindContainerWidget == nullptr){
m_pFaultFindContainerWidget = new FaultFindContainerWindow(ui->page_4);
// m_pFaultFindContainerWidget->setStyleSheet("background-color:green;");
pPageLayout->addWidget(m_pFaultFindContainerWidget);
connect(m_pFaultFindContainerWidget,&FaultFindContainerWindow::signEscMainWindow,this,&MainWindow::slotEscMainWindow);
connect(m_pFaultFindContainerWidget,&FaultFindContainerWindow::signSetLabelText,this,&MainWindow::setLabelText);
}
ui->centerStackedWidget->setCurrentIndex(4);//会自动添加焦点
setLabelText(3);
}
程序运行的效果是:
本该适应堆栈窗口的大小,但是却明显和堆栈窗口不一样大。
原因
因为没有将创建的堆栈窗口添加到父窗口所在的布局中,所以只展示堆栈窗口本身的大小。
解决方法
1.将堆栈窗口添加到一个水平布局中,使其能够和父窗口一样的大小。
2.设置堆栈窗口的大小和其父窗口的大小一样大。
我采用布局的方式,因为不想一级一级的传递窗口大小的参数。修改后的代码如下:
void MainWindow::faultFind()
{
if(m_pFaultFindContainerWidget == nullptr){
QHBoxLayout* pPageLayout = new QHBoxLayout(ui->page_4);
pPageLayout->setContentsMargins(0,0,0,0);
pPageLayout->setSpacing(0);
m_pFaultFindContainerWidget = new FaultFindContainerWindow(ui->page_4);
// m_pFaultFindContainerWidget->setStyleSheet("background-color:green;");
pPageLayout->addWidget(m_pFaultFindContainerWidget);
connect(m_pFaultFindContainerWidget,&FaultFindContainerWindow::signEscMainWindow,this,&MainWindow::slotEscMainWindow);
connect(m_pFaultFindContainerWidget,&FaultFindContainerWindow::signSetLabelText,this,&MainWindow::setLabelText);
}
ui->centerStackedWidget->setCurrentIndex(4);//会自动添加焦点
setLabelText(3);
}
当将堆栈窗口添加到父窗口ui->page_4中的时候,给父窗口ui->page_4添加了水平布局,将堆栈窗口容器类对象m_pFaultFindContainerWidget 添加到父窗口ui->page_4的布局中,这样堆栈窗口容器类对象m_pFaultFindContainerWidget 的大小和其父窗口ui->page_4一样大。
此时再去运行程序如下:
总结
向堆栈窗口中添加了窗口后,堆栈窗口中添加的子窗口显示的大小并没有和其所在的堆栈窗口一样大。
(可能原因:窗口的大小不对;该问题的原因:窗口的大小不对,可采用传入参数设置窗口大小,也可采用在堆栈窗口中添加布局,然后将要添加到堆栈窗口中的窗口添加到布局中,窗口大小就和堆栈窗口的大小一致)
场景
当向堆栈窗口中添加自己自定义的窗口类作为堆栈窗口的子窗口时,我以为设置了自定义窗口的父窗口就不用调用addWidget来向堆栈窗口中添加自定义的窗口了,但实际上还是需要调用函数addWidget向堆栈窗口中添加自定义的窗口,若是不调用该addWidget函数就会出现添加的多个自定义的窗口都显示在堆栈窗口的下标为0的第一个子窗口中,出现窗口的重叠。
下面是创建堆栈窗口,并将自己自定义的窗口,添加到堆栈窗口中的代码,没调用addWidget前是这样的。
void FaultFindContainerWindow::createStackedWidget()
{
m_pFaultFindStackedWidget = new QStackedWidget(this);
// m_pFaultFindStackedWidget->setStyleSheet("background-color:blue;");
m_pFaultFindWidget = new FaultFindForm(m_pFaultFindStackedWidget);//不设父对象,事件不能传递下去,对象树是事件传度的基础
// m_pFaultFindWidget->setStyleSheet("background-color:grey;");
connect(m_pFaultFindWidget,&FaultFindForm::signEscMainWindow,this,&FaultFindContainerWindow::signEscMainWindow);
connect(m_pFaultFindWidget,&FaultFindForm::signEnterScanWindow,this,&FaultFindContainerWindow::slotEnterScanWindow);
m_pScanChannelWidget = new ScanChannelForm(m_pFaultFindStackedWidget);
ModuleIntegrationController::getInstance()->registerScanChannelWidgetAndBindSignal(m_pScanChannelWidget);
connect(m_pScanChannelWidget,&ScanChannelForm::signEscPreviousWindow,this,&FaultFindContainerWindow::slotEscPreviousWindow);
connect(m_pScanChannelWidget,&ScanChannelForm::signSetLabelText,this,&FaultFindContainerWindow::signSetLabelText);
QHBoxLayout* pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0,0,0,0);
pLayout->setSpacing(0);
pLayout->addWidget(m_pFaultFindStackedWidget);//没有该布局,子窗口不能时应堆栈窗口大小
// qDebug()<<"堆栈窗口m_pFaultFindStackedWidget大小:"<<m_pFaultFindStackedWidget->size()<<" "<<size();
m_pFaultFindStackedWidget->setCurrentIndex(0);
}
上面只给出关键性代码。运行程序之后,效果如下:
此时还需要调用addWidget函数将自定义窗口m_pFaultFindWidget 和m_pScanChannelWidget 添加到堆栈窗口中。代码变为:
void FaultFindContainerWindow::createStackedWidget()
{
m_pFaultFindStackedWidget = new QStackedWidget(this);
// m_pFaultFindStackedWidget->setStyleSheet("background-color:blue;");
m_pFaultFindWidget = new FaultFindForm(m_pFaultFindStackedWidget);//不设父对象,事件不能传递下去,对象树是事件传度的基础
// m_pFaultFindWidget->setStyleSheet("background-color:grey;");
connect(m_pFaultFindWidget,&FaultFindForm::signEscMainWindow,this,&FaultFindContainerWindow::signEscMainWindow);
connect(m_pFaultFindWidget,&FaultFindForm::signEnterScanWindow,this,&FaultFindContainerWindow::slotEnterScanWindow);
m_pScanChannelWidget = new ScanChannelForm(m_pFaultFindStackedWidget);
ModuleIntegrationController::getInstance()->registerScanChannelWidgetAndBindSignal(m_pScanChannelWidget);
connect(m_pScanChannelWidget,&ScanChannelForm::signEscPreviousWindow,this,&FaultFindContainerWindow::slotEscPreviousWindow);
connect(m_pScanChannelWidget,&ScanChannelForm::signSetLabelText,this,&FaultFindContainerWindow::signSetLabelText);
m_pFaultFindStackedWidget->addWidget(m_pFaultFindWidget);//即使设置了父窗口,也需要将窗口添加到堆栈窗口中,否则窗口都会添加到同一堆栈子窗口,出现窗口重叠
m_pFaultFindStackedWidget->addWidget(m_pScanChannelWidget);
QHBoxLayout* pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0,0,0,0);
pLayout->setSpacing(0);
pLayout->addWidget(m_pFaultFindStackedWidget);//没有该布局,子窗口不能时应堆栈窗口大小
// qDebug()<<"堆栈窗口m_pFaultFindStackedWidget大小:"<<m_pFaultFindStackedWidget->size()<<" "<<size();
m_pFaultFindStackedWidget->setCurrentIndex(0);
}
这样窗口便运行正常了。
补充
向堆栈窗口中添加了窗口后,堆栈窗口中添加的窗口没有显示出来。
(可能原因:1.没有指明父窗口;2.窗口的大小不对;该问题的原因:窗口的大小不对,可采用传入参数设置窗口大小,也可采用在堆栈窗口中添加布局,然后将要添加到堆栈窗口中的窗口添加到布局中,窗口大小就和堆栈窗口的大小一致)
当自定义的控件作为另一个类的子控件时,想要在窗口按下按键,事件在自定义的控件中处理,不能直接在自定义的控件中重写按键事件,而是要在自定义控件所在的窗口中重写按键事件,在相应的按键事件中用子控件调用相应的函数。
下面记录一个示例:
当一个窗口中含有一个堆栈窗口,我将其称为堆栈窗口容器类,该堆栈窗口容器类中的堆栈窗口添加子窗口时,其中一个子窗口又是堆栈窗口容器类,向该堆栈窗口容器类中添加了子窗口之后,设置当前堆栈窗口容器类中堆栈窗口中显示的子窗口。代码如下(只有关键性代码):
SpeechContainerWidget也是一个堆栈窗口容器类,
void SpeechContainerWidget::createStackedWidget()
{
m_pSpeechStackedWidget = new QStackedWidget(this);
m_pSpeechBandContainerWidget = new SpeechBandContainerWidget(m_pSpeechStackedWidget);//此类为堆栈窗口类
connect(m_pSpeechBandContainerWidget,&SpeechBandContainerWidget::signEscModeSelectedWindow,this,&SpeechContainerWidget::signEscModeSelectedWindow);
m_pSpeechStackedWidget->addWidget(m_pSpeechBandContainerWidget);
QHBoxLayout* pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0,0,0,0);
pLayout->setSpacing(0);
pLayout->addWidget(m_pSpeechStackedWidget);
m_pSpeechStackedWidget->setCurrentIndex(0);
// m_pSpeechStackedWidget->currentWidget()->setFocus();//这行放开注释之后焦点不能在m_pSpeechWidget 指向的第一个窗口上,会覆盖之前设置的焦点
}
堆栈窗口容器类SpeechBandContainerWidget的界面是这样的:
SpeechBandContainerWidget::SpeechBandContainerWidget(QWidget* parent)
:QWidget(parent)
{
createStackedWidget();
}
void SpeechBandContainerWidget::createStackedWidget()
{
QString strBand = InterfaceSelectedParams::getInstance()->getSelectedBand();
QStringList strBandList = getBandFromComplexBand(strBand);
m_pStackedWidget = new QStackedWidget(this);
for(const auto& strBand:strBandList){
m_pSpeechWidget = new SpeechForm(m_pStackedWidget);
connect(m_pSpeechWidget,&SpeechForm::signEscModeSelectedWindow,this,&SpeechBandContainerWidget::signEscModeSelectedWindow);
m_pSpeechWidget->setValues(getParamsBySpecificBand(strBand));
m_pStackedWidget->addWidget(m_pSpeechWidget);
}
QHBoxLayout* pLayout = new QHBoxLayout(this);
pLayout->setContentsMargins(0,0,0,0);
pLayout->setSpacing(0);
pLayout->addWidget(m_pStackedWidget);
m_pStackedWidget->setCurrentIndex(0);
m_pStackedWidget->currentWidget()->setFocus();
}
这里要提的是当SpeechBandContainerWidget这个堆栈窗口容器类作为SpeechContainerWidget这个堆栈窗口容器类中堆栈窗口m_pSpeechStackedWidget 的子窗口后,在SpeechBandContainerWidget这个堆栈窗口容器类的堆栈窗口创建完子窗口后,已经设置了当前堆栈窗口容器类中堆栈窗口显示的子窗口,且让当前显示的子窗口获取焦点。
起初在SpeechContainerWidget堆栈窗口容器类的堆栈窗口创建完子窗口m_pSpeechBandContainerWidget ,设置了当前显示的窗口,并且也设置了焦点,但是会出现焦点不能按照预期在SpeechBandContainerWidget类中的堆栈窗口的第一个窗口中。因为SpeechBandContainerWidget::createStackedWidget()是在SpeechContainerWidget类中new的时候调用的,导致先设了SpeechBandContainerWidget类中堆栈窗口的第一个子窗口上又焦点,而后又将焦点设置在了SpeechContainerWidget类中堆栈窗口中第一个子窗口m_pSpeechBandContainerWidget 上,预期是希望焦点在m_pFaultFindSpeechWidget 类类型的第一个窗口上。