From 75982278b41c377089c701dac5d5e1ab99f530b7 Mon Sep 17 00:00:00 2001 From: codeboss <2422523675@qq.com> Date: Fri, 9 Feb 2024 16:45:40 +0800 Subject: [PATCH] =?UTF-8?q?bug=EF=BC=8C=E8=AE=BE=E7=BD=AE=E7=88=B6?= =?UTF-8?q?=E5=BC=95=E7=94=A8=E4=B8=BAnull=E7=9A=84=E6=97=B6=E5=80=99?= =?UTF-8?q?=E5=BC=95=E5=8F=91visible=E8=BF=87=E7=A8=8B=EF=BC=8C=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=85=B6=E4=BB=96=E8=A7=86=E5=9B=BE=E8=A2=AB=E5=BD=92?= =?UTF-8?q?=E7=B1=BB=E5=88=B0=E7=A9=BA=E9=97=B2=E8=A7=86=E5=9B=BE=E7=B1=BB?= =?UTF-8?q?=E5=88=AB=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtNovelDesc.pro.user | 2 +- libSplitView/acceptpanel.cpp | 2 +- libSplitView/dockpanel.cpp | 1 + libSplitView/splitpanel.cpp | 10 +-- libSplitView/splitview_interface.h | 25 ++++--- libSplitView/splitwindow.cpp | 106 ++++++++++++++++++----------- libSplitView/splitwindow.h | 16 +++-- u_test/main.cpp | 3 +- 8 files changed, 102 insertions(+), 63 deletions(-) diff --git a/QtNovelDesc.pro.user b/QtNovelDesc.pro.user index 672200a..181e8e0 100644 --- a/QtNovelDesc.pro.user +++ b/QtNovelDesc.pro.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/libSplitView/acceptpanel.cpp b/libSplitView/acceptpanel.cpp index 69b1bb7..42bbb0e 100644 --- a/libSplitView/acceptpanel.cpp +++ b/libSplitView/acceptpanel.cpp @@ -112,7 +112,7 @@ void accept_panel::AcceptPanel::dragEnterEvent(QDragEnterEvent *ev) void accept_panel::AcceptPanel::dropEvent(QDropEvent *ev) { auto view = view_manager->adjustView(); - if(view){ + if(view && anchor_view != view){ switch (target_type) { case HoverType::CUBE_LEFT: view_manager->doRetrieve(view); diff --git a/libSplitView/dockpanel.cpp b/libSplitView/dockpanel.cpp index 087f860..2e66a22 100644 --- a/libSplitView/dockpanel.cpp +++ b/libSplitView/dockpanel.cpp @@ -146,6 +146,7 @@ void DockableView::adjustAccept(const QPoint &pos) void DockableView::closeAccept() { + this->manager_inst->doRetrieve(this); this->manager_inst->doClose(this); } diff --git a/libSplitView/splitpanel.cpp b/libSplitView/splitpanel.cpp index 579a631..0bec848 100644 --- a/libSplitView/splitpanel.cpp +++ b/libSplitView/splitpanel.cpp @@ -79,10 +79,11 @@ bool SplitPanel::isVisible() const void SplitPanel::initViews(ViewRes *a, ViewRes *b) { - this->split_member = std::make_pair(a, b); - a->setParentRes(this); b->setParentRes(this); + this->split_member = std::make_pair(a, b); + + this->sync_status(); } QWidget *SplitPanel::widget() const { return const_cast(this); } @@ -132,9 +133,9 @@ void SplitPanel::replaceView(ViewRes *_new, ViewRes *_old) throw new SimpleException("运行异常", "指定替换的视图不属于本组件"); } - _new->setParentRes(this); auto elsev = except(_old); - switch (std::get<1>(elsev)) { + _new->setParentRes(this); + switch (elsev.second) { case 0: this->split_member = std::make_pair(elsev.first, _new); break; @@ -142,6 +143,7 @@ void SplitPanel::replaceView(ViewRes *_new, ViewRes *_old) this->split_member = std::make_pair(_new, elsev.first); } + _old->setParentRes(nullptr); sync_status(); this->update(); } diff --git a/libSplitView/splitview_interface.h b/libSplitView/splitview_interface.h index ce77739..128e424 100644 --- a/libSplitView/splitview_interface.h +++ b/libSplitView/splitview_interface.h @@ -128,16 +128,16 @@ namespace split_frame { virtual ~SplitView() = default; /** - * @brief 载入视图成员 + * @brief 载入视图成员,构建父子引用关系 * @param a 成员视图a * @param b 成员视图b */ virtual void initViews(ViewRes *a, ViewRes *b) = 0; /** - * @brief 构建子视图 - * @param old 不为nullptr - * @param view 不为nullptr + * @brief 使用新视图替换指定视图,重构呈现树 + * @param view 实例需要属于闲置视图,调用完成被重建父子引用 + * @param pos 实例属于呈现树,调用完成将被解除父子引用 */ virtual void replaceView(ViewRes *_new, ViewRes *_old) = 0; @@ -231,23 +231,30 @@ namespace split_frame { */ virtual void appendPresentView(ViewBase *inst) = 0; + /** + * @brief 测试指定视图是否处于呈现状态 + * @param inst 指定视图 + */ + virtual bool isPresented(ViewBase *inst) const = 0; + /** * @brief 回收视图显示,转换视图为自由(闲置)状态 - * @param inst + * @param inst 视图实例需要确实处于可视状态(临时显示或位于呈现树内) */ virtual void doRetrieve(ViewBase *inst) = 0; /** * @brief 回收视图,清除内存实例 + * @param inst 视图实例需要处于闲置状态 */ virtual void doClose(ViewBase *inst) = 0; /** - * @brief 替换指定视图 - * @param view - * @param old + * @brief 使用指定视图合并显示 + * @param view 需要合并的闲置视图 + * @param pos 指定合并目标位置 */ - virtual void siblingAttach(ViewBase *view, ViewRes *pos, SplitType ori) = 0; + virtual void siblingAttach(ViewBase *view, ViewBase *pos, SplitType ori) = 0; }; } // namespace SplitFrame diff --git a/libSplitView/splitwindow.cpp b/libSplitView/splitwindow.cpp index 5e1549c..41edaef 100644 --- a/libSplitView/splitwindow.cpp +++ b/libSplitView/splitwindow.cpp @@ -17,26 +17,34 @@ using namespace split_window; using namespace split_frame; -void SplitWindow::setRoot(split_frame::ViewRes *inst) + +SplitWindow::SplitWindow(QWidget *parent) : QMainWindow(parent), view_root(nullptr), accept_port(new accept_panel::AcceptPanel(this, this)) { + this->view_root = nullptr; + accept_port->setVisible(false); +} + +SplitWindow::~SplitWindow() {} + +void SplitWindow::tempShow(split_frame::DockType t, split_frame::ViewBase *target) +{ + this->temp_show = target; + target->setVisible(true); +} + +void SplitWindow::setPresentTarget(split_frame::ViewRes *inst) { if(inst){ - this->view_root = inst; inst->setParentRes(nullptr); this->setCentralWidget(inst->widget()); } else{ this->takeCentralWidget(); - this->view_root = nullptr; } -} -SplitWindow::SplitWindow(QWidget *parent) : QMainWindow(parent), view_root(nullptr), accept_port(new accept_panel::AcceptPanel(this, this)) { - this->setRoot(nullptr); - accept_port->setVisible(false); + this->view_root = inst; + this->update(); } -SplitWindow::~SplitWindow() {} - bool SplitWindow::eventFilter(QObject *sender, QEvent *ev) { switch (ev->type()) { @@ -51,7 +59,7 @@ bool SplitWindow::eventFilter(QObject *sender, QEvent *ev) global_pos = dynamic_cast(sender)->mapToGlobal(evn_pos); } - for (auto &cmp : this->views_store) { + for (auto &cmp : this->presents_store) { auto local_pos = cmp->widget()->mapFromGlobal(global_pos); auto rect_shape = cmp->outlineRect(); rect_shape.moveTopLeft(QPointF()); @@ -89,57 +97,70 @@ void SplitWindow::removeListener(split_frame::FreedomViewsListener *lsn) void SplitWindow::appendPresentView(split_frame::ViewBase *inst) { if(inst) - this->views_store[inst->hashCode()] = inst; + this->presents_store[inst->hashCode()] = inst; } void SplitWindow::removePresentView(split_frame::ViewBase *inst) { if(inst) - this->views_store.remove(inst->hashCode()); + this->presents_store.remove(inst->hashCode()); } -void SplitWindow::present_remove(split_frame::ViewRes *inst) +bool SplitWindow::isPresented(split_frame::ViewBase *inst) const { - // 面板树中间节点 - if(inst != view_root && inst->parentRes()){ + return inst && presents_store.contains(inst->hashCode()); +} + + +#include +void SplitWindow::doRetrieve(split_frame::ViewBase *inst) +{ + if(!isPresented(inst)){ + throw new Config::SimpleException("参数错误", "无法回收空闲视图!"); + } + + // 呈现视图结构调整 + if(inst == temp_show){ + temp_show->setVisible(false); + return; + } + else if (inst == view_root) { + setPresentTarget(); + inst->setParentRes(nullptr); + } + else if(inst->parentRes() == view_root){ + auto pinst_root = inst->parentRes(); + + auto remains = pinst_root->except(inst); + inst->setParentRes(nullptr); + + setPresentTarget(remains.first); + delete pinst_root; + } + else if(inst->parentRes()){ auto pinst = inst->parentRes(); auto remains = pinst->except(inst); - remains.first->setParentRes(nullptr); inst->setParentRes(nullptr); - // 父节点不是根节点 auto ppinst = pinst->parentRes(); - if (ppinst) { - ppinst->replaceView(remains.first, pinst); - } else { - this->setRoot(remains.first); - } + ppinst->replaceView(remains.first, pinst); delete pinst; } - else if(inst == view_root){ - setRoot(nullptr); - inst->setParentRes(nullptr); - } -} -void SplitWindow::doRetrieve(split_frame::ViewBase *inst) -{ - // 呈现视图结构调整 - present_remove(inst); - - // 回收当前视图 - for(auto &lsn : listener_list) - lsn->freedomAppend(inst); inst->setParentRes(nullptr); inst->setVisible(false); removePresentView(inst); + + // 当前视图已被回收 + for(auto &lsn : listener_list) + lsn->freedomAppend(inst); } void SplitWindow::doClose(split_frame::ViewBase *inst) { - // 呈现视图结构调整 - present_remove(inst); + if(isPresented(inst)) + throw new Config::SimpleException("编码异常", "不能关闭非空闲视图!"); // 回收当前视图 for(auto &lsn : listener_list) @@ -149,11 +170,16 @@ void SplitWindow::doClose(split_frame::ViewBase *inst) delete inst; } -void SplitWindow::siblingAttach(ViewBase *view, ViewRes *pos, SplitType ori) +void SplitWindow::siblingAttach(ViewBase *view, ViewBase *pos, SplitType ori) { - auto remains_frm = pos->parentRes(); - doRetrieve(view); + if(isPresented(view) && view != temp_show){ + throw new Config::SimpleException("参数错误", "只能使用空闲视图吸附重组!"); + } + if(!isPresented(pos)){ + throw new Config::SimpleException("参数错误", "不能依据空闲视图吸附重组!"); + } + auto remains_frm = pos->parentRes(); auto split_slot = new split_panel::SplitPanel(this, ori); remains_frm->replaceView(split_slot, pos); diff --git a/libSplitView/splitwindow.h b/libSplitView/splitwindow.h index e50a52d..9294634 100644 --- a/libSplitView/splitwindow.h +++ b/libSplitView/splitwindow.h @@ -19,12 +19,12 @@ namespace split_window { private: QList listener_list; - QHash views_store; - split_frame::ViewRes *view_root; + + QHash presents_store; accept_panel::AcceptPanel *const accept_port; + split_frame::ViewRes *view_root = nullptr, *temp_show = nullptr; split_frame::ViewBase *adjust_target = nullptr; - void present_remove(split_frame::ViewRes *inst); public: SplitWindow(QWidget *parent = nullptr); @@ -39,8 +39,11 @@ namespace split_window { void tempShow(split_frame::DockType t, split_frame::ViewBase *target); - void setRoot(split_frame::ViewRes *inst); - + /** + * @brief 设置指定视图为根视图或者取消 + * @param inst + */ + void setPresentTarget(split_frame::ViewRes *inst = nullptr); bool eventFilter(QObject *sender, QEvent *ev) override; @@ -50,9 +53,10 @@ namespace split_window { virtual void removeListener(split_frame::FreedomViewsListener *lsn) override; virtual void appendPresentView(split_frame::ViewBase *inst) override; virtual void removePresentView(split_frame::ViewBase *inst) override; + virtual bool isPresented(split_frame::ViewBase *inst) const override; virtual void doRetrieve(split_frame::ViewBase *inst) override; virtual void doClose(split_frame::ViewBase *inst) override; - virtual void siblingAttach(split_frame::ViewBase *view, split_frame::ViewRes *pos, split_frame::SplitType ori) override; + virtual void siblingAttach(split_frame::ViewBase *view, split_frame::ViewBase *pos, split_frame::SplitType ori) override; virtual split_frame::ViewBase *adjustView() const override; virtual void setAdjustView(split_frame::ViewBase *target) override; }; diff --git a/u_test/main.cpp b/u_test/main.cpp index 556b32e..57a4a07 100644 --- a/u_test/main.cpp +++ b/u_test/main.cpp @@ -20,12 +20,11 @@ int main(int argc, char *argv[]) { split_window::SplitWindow w; auto spb = new split_panel::SplitPanel(&w, split_frame::SplitType::SPLIT_H_LFIRST); - w.setRoot(spb); - auto bview = new dock_panel::DockableView(&w, new QWidget, true); auto dview = new dock_panel::DockableView(&w, new QWidget, true); spb->initViews(bview, dview); + w.setPresentTarget(spb); a.installEventFilter(&w); w.show();