Refactor QDicomViewer, add fusion button check logic.

This commit is contained in:
Krad
2022-07-08 17:52:30 +08:00
parent 850c888e1e
commit 206d6ba7ef
6 changed files with 564 additions and 747 deletions

View File

@@ -35,6 +35,8 @@ void ImageViewManager::add(DicomImageView *view) {
connect(view, &DicomImageView::onViewDoubleClick,
this, &ImageViewManager::viewDoubleClicked);
connect(view, &DicomImageView::afterViewCleared,this, &ImageViewManager::viewCleared);
connect(view, &DicomImageView::onDragDrop, [=](DicomImageView *view, const std::string &id) {
setCurrentView(view);
viewReload(id);
@@ -68,6 +70,7 @@ void ImageViewManager::setCurrentView(DicomImageView *view) {
currentView = view;
currentView->setHighlight(true);
emit currentViewChanged(currentView->getSeriesInstance()->getUniqueID());
checkCurrentViewFusion();
}
}
@@ -218,6 +221,11 @@ void ImageViewManager::viewReload(const std::string &unique_info) {
DicomLoader *helper = DicomLoader::GetInstance();
currentView->loadSeries(helper->getSeriesImageSet(unique_info));
currentView->render();
checkCurrentViewFusion();
}
void ImageViewManager::viewCleared() {
emit fusionCheckStateChanged(false);
}
void ImageViewManager::setInteractionMode(int InteractionMode) {
@@ -292,15 +300,16 @@ void ImageViewManager::switchFusion() {
}
}
bool ImageViewManager::checkCurrentViewFusion() {
void ImageViewManager::checkCurrentViewFusion() {
for (int i = 0; i < getViewCount(); ++i) {
if (getView(i) == getCurrentView()) continue;
DicomImageView *overlap_view = getView(i);
if (currentView->checkFusion(overlap_view)) {
currentFusionView = overlap_view;
return true;
emit fusionCheckStateChanged(true);
return;
}
}
currentFusionView = nullptr;
return false;
emit fusionCheckStateChanged(false);
}

View File

@@ -40,7 +40,7 @@ public:
return currentView;
}
bool checkCurrentViewFusion();
void checkCurrentViewFusion();
int getViewCount() {
return vList.size();
@@ -68,6 +68,8 @@ public:
void viewReload(const std::string &unique_info);
void viewCleared();
void setInteractionMode(int InteractionMode);
void renderAll();
@@ -103,6 +105,7 @@ public:
signals:
void currentViewChanged(const std::string& seriesID);
void fusionCheckStateChanged(bool able);
private:
QList<DicomImageView *> vList;

View File

@@ -194,7 +194,7 @@ void DicomImageView::scrollBarValueChanged(int slice) {
void DicomImageView::viewCleared() {
resetView();
emit afterViewClear(this);
emit afterViewCleared(this);
}
void DicomImageView::doubleClicked() {

View File

@@ -167,7 +167,7 @@ public:
signals:
void afterViewClear(DicomImageView *view);
void afterViewCleared(DicomImageView *view);
void onViewClick(DicomImageView *view);

View File

@@ -11,64 +11,9 @@
#include "UI/Widget/gridpopwidget.h"
#include "UI/Widget/cine/pqVCRToolbar.h"
/************************************************************************
* Consider:
* 1. [Done]series id only maps to a single instance, this situation needs to be improved.
* 2. [Done]Corner Info Auto tune
* 3. [Undone]disable open icon when dicom data loading is not finished
* 4. [Done]Import from PACS inherits Qthread in the near future!
* Notice:
* 1. You'd better set to new instance before delete the older, may leads to crash problem.
* 2.
* Bug:
* 1. getRelevantViewList() should consider in memory not in view instance
/************************************************************************/
#define SINGLE_INSTANCE 1
#define addbutton(name,png)\
QToolButton* btn##name = new QToolButton(this);\
{\
QPixmap map(png);\
btn##name->setIcon(QIcon(map));\
btn##name->setMinimumSize(QSize(48, 48));\
btn##name->setMaximumSize(QSize(48, 48));\
btn##name->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);\
this->ui->toolBar->addWidget(btn##name);\
}\
#define addGroupedButton(name,png,group)\
QToolButton* btn##name = new QToolButton(this);\
{\
QPixmap map(png);\
btn##name->setIcon(QIcon(map));\
btn##name->setCheckable(true);\
btn##name->setAutoExclusive(true);\
btn##name->setMinimumSize(QSize(48, 48));\
btn##name->setMaximumSize(QSize(48, 48));\
btn##name->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);\
group->addButton(btn##name);\
this->ui->toolBar->addWidget(btn##name);\
}\
#define addbutton2(name,png)\
QToolButton* btn##name = new QToolButton(this);\
{\
QPixmap map(png);\
btn##name->setIcon(QIcon(map));\
btn##name->setMinimumSize(QSize(25, 25));\
btn##name->setMaximumSize(QSize(25, 25));\
this->ui->toolBar->addWidget(btn##name); \
}\
QDicomViewer::QDicomViewer(QWidget *parent) : QMainWindow(parent),
ui(new Ui::QDicomViewerClass),
m_import(nullptr)
{
m_import(nullptr) {
ui->setupUi(this);
this->statusBar()->showMessage(tr("Ready"));
QWidget::setWindowTitle(Project_NAME);
@@ -101,80 +46,102 @@ m_import(nullptr)
QDicomViewer::~QDicomViewer() {
}
void QDicomViewer::Initial() {
this->createToolButton();
this->SetupConnections();
}
void QDicomViewer::loadStyleSheet(const QString& sheetName)
{
void QDicomViewer::loadStyleSheet(const QString &sheetName) {
QFile file(":/StyleSheet/" + sheetName + ".qss");
file.open(QFile::ReadOnly);
if (file.isOpen())
{
if (file.isOpen()) {
QString styleSheet = this->styleSheet();
styleSheet += QLatin1String(file.readAll());
this->setStyleSheet(styleSheet);
}
}
void QDicomViewer::Initial()
{
this->createToolButton();
this->SetupConnections();
void QDicomViewer::createToolButton() {
#define addbutton(name, png)\
QToolButton* btn##name = new QToolButton(this);\
{\
QPixmap map(png);\
btn##name->setIcon(QIcon(map));\
btn##name->setMinimumSize(QSize(48, 48));\
btn##name->setMaximumSize(QSize(48, 48));\
btn##name->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);\
this->ui->toolBar->addWidget(btn##name);\
}
#define addGroupedButton(name, png, group)\
QToolButton* btn##name = new QToolButton(this);\
{\
QPixmap map(png);\
btn##name->setIcon(QIcon(map));\
btn##name->setCheckable(true);\
btn##name->setAutoExclusive(true);\
btn##name->setMinimumSize(QSize(48, 48));\
btn##name->setMaximumSize(QSize(48, 48));\
btn##name->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);\
group->addButton(btn##name);\
this->ui->toolBar->addWidget(btn##name);\
}
#define addbutton2(name, png)\
QToolButton* btn##name = new QToolButton(this);\
{\
QPixmap map(png);\
btn##name->setIcon(QIcon(map));\
btn##name->setMinimumSize(QSize(25, 25));\
btn##name->setMaximumSize(QSize(25, 25));\
this->ui->toolBar->addWidget(btn##name); \
}
void QDicomViewer::createToolButton()
{
//this->ui->vcr_toolbar->setMovable(true);
//this->ui->vcr_toolbar->setToolButtonStyle(Qt::ToolButtonIconOnly);
ui->toolBar->setContextMenuPolicy(Qt::ContextMenuPolicy::PreventContextMenu);
ui->toolBar->setFixedHeight(VCRHelper::toolbar_Height);
ui->toolBar->setMovable(false);
ui->toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
addbutton(file, ":/InfiniteViewer/Icon/openfile.png");
addbutton(import, ":/InfiniteViewer/Icon/import.png");
addbutton(save, ":/InfiniteViewer/Icon/save.png");
addbutton(file, ":/InfiniteViewer/Icon/openfile.png")
addbutton(import, ":/InfiniteViewer/Icon/import.png")
addbutton(save, ":/InfiniteViewer/Icon/save.png")
this->ui->toolBar->addSeparator();
addbutton(grid, ":/InfiniteViewer/Icon/grid.png");
addbutton(sync, ":/InfiniteViewer/Icon/sync/sync_dis.png");
addbutton(anno, ":/InfiniteViewer/Icon/anno.png");
addbutton(grid, ":/InfiniteViewer/Icon/grid.png")
addbutton(sync, ":/InfiniteViewer/Icon/sync/sync_dis.png")
addbutton(anno, ":/InfiniteViewer/Icon/anno.png")
this->ui->toolBar->addSeparator();
QButtonGroup *modegroup = new QButtonGroup(this);
addGroupedButton(slice, ":/InfiniteViewer/Icon/slice.png", modegroup);
addGroupedButton(windowlevel, ":/InfiniteViewer/Icon/windowlevel.png", modegroup);
addGroupedButton(pan, ":/InfiniteViewer/Icon/pan.png", modegroup);
addGroupedButton(zoom, ":/InfiniteViewer/Icon/zoom.png", modegroup);
addGroupedButton(measure, ":/InfiniteViewer/Icon/distance.png", modegroup);
addbutton(empty, ":/InfiniteViewer/Icon/trashbin.png");
addGroupedButton(slice, ":/InfiniteViewer/Icon/slice.png", modegroup)
addGroupedButton(windowlevel, ":/InfiniteViewer/Icon/windowlevel.png", modegroup)
addGroupedButton(pan, ":/InfiniteViewer/Icon/pan.png", modegroup)
addGroupedButton(zoom, ":/InfiniteViewer/Icon/zoom.png", modegroup)
addGroupedButton(measure, ":/InfiniteViewer/Icon/distance.png", modegroup)
addbutton(empty, ":/InfiniteViewer/Icon/trashbin.png")
this->ui->toolBar->addSeparator();
addbutton(flip, ":/InfiniteViewer/Icon/flip.png");
addbutton(cine, ":/InfiniteViewer/Icon/cine.png");
addbutton(fusion, ":/InfiniteViewer/Icon/fusion.png");
addbutton(MPR, ":/InfiniteViewer/Icon/MPR.png");
addbutton(flip, ":/InfiniteViewer/Icon/flip.png")
addbutton(cine, ":/InfiniteViewer/Icon/cine.png")
addbutton(fusion, ":/InfiniteViewer/Icon/fusion.png")
addbutton(MPR, ":/InfiniteViewer/Icon/MPR.png")
QWidget *spacer = new QWidget(this);
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
this->ui->toolBar->addWidget(spacer);
//this->ui->toolBar_2->setFixedHeight(VCRHelper::toolbtn2_Size);
//this->ui->toolBar_2->setMovable(false);
//this->ui->toolBar_2->setToolButtonStyle(Qt::ToolButtonIconOnly);
act_num_of_minimize = ui->toolBar->actions().count();
addbutton2(minimize, ":/InfiniteViewer/Icon/minimize.png");
addbutton2(minimize, ":/InfiniteViewer/Icon/minimize.png")
act_num_of_maximize = ui->toolBar->actions().count();
addbutton2(maximize, ":/InfiniteViewer/Icon/maximize-restore.png");
addbutton2(maximize, ":/InfiniteViewer/Icon/maximize-restore.png")
act_num_of_close = ui->toolBar->actions().count();
addbutton2(close, ":/InfiniteViewer/Icon/close.png");
addbutton2(close, ":/InfiniteViewer/Icon/close.png")
act_num_of_fullscreen = ui->toolBar->actions().count();
addbutton2(fullscreen, ":/InfiniteViewer/Icon/full_screen.png");
addbutton2(fullscreen, ":/InfiniteViewer/Icon/full_screen.png")
ui->toolBar->actions().at(act_num_of_minimize)->setVisible(false);
ui->toolBar->actions().at(act_num_of_maximize)->setVisible(false);
@@ -204,11 +171,11 @@ void QDicomViewer::createToolButton()
this->SetupMinimizeTool(btnminimize);
this->SetupCloseTool(btnclose);
connect(btnMPR,&QToolButton::clicked,ui->viewContainer->getViewManager(), &ImageViewManager::switchSliceOrientation);
connect(btnMPR, &QToolButton::clicked, ui->viewContainer->getViewManager(),
&ImageViewManager::switchSliceOrientation);
}
void QDicomViewer::SetupFullScreenTool(QToolButton* btnfullscreen)
{
void QDicomViewer::SetupFullScreenTool(QToolButton *btnfullscreen) {
btnfullscreen->setToolTip(QString("Full screen"));
connect(btnfullscreen, &QToolButton::clicked, this, [=] {
ui->toolBar->actions().at(act_num_of_fullscreen)->setVisible(false);
@@ -220,8 +187,7 @@ void QDicomViewer::SetupFullScreenTool(QToolButton* btnfullscreen)
});
}
void QDicomViewer::SetupMaximizeTool(QToolButton* btnmaximize)
{
void QDicomViewer::SetupMaximizeTool(QToolButton *btnmaximize) {
btnmaximize->setToolTip(QString("Exit full screen mode"));
connect(btnmaximize, &QToolButton::clicked, this, [=] {
@@ -234,28 +200,19 @@ void QDicomViewer::SetupMaximizeTool(QToolButton* btnmaximize)
});
}
void QDicomViewer::SetupMinimizeTool(QToolButton* btnminimize)
{
void QDicomViewer::SetupMinimizeTool(QToolButton *btnminimize) {
btnminimize->setToolTip(QString("Minimize"));
connect(btnminimize, &QToolButton::clicked, this, [=] {
setWindowState(Qt::WindowState::WindowMinimized);
});
}
void QDicomViewer::SetupCloseTool(QToolButton* btnclose)
{
void QDicomViewer::SetupCloseTool(QToolButton *btnclose) {
btnclose->setToolTip(QString("Close"));
connect(btnclose, &QToolButton::clicked, this, [=] {
close();
});
connect(btnclose, &QToolButton::clicked, this, &QWidget::close);
}
void QDicomViewer::SetupAnnoTool(QToolButton* annoBtn)
{
void QDicomViewer::SetupAnnoTool(QToolButton *annoBtn) {
//主要设置了四角标签的操作逻辑
annoBtn->setToolTip(QString("Toggle annotations"));
//视窗操作,显隐脚注
@@ -268,8 +225,7 @@ void QDicomViewer::SetupAnnoTool(QToolButton* annoBtn)
//视窗操作,显隐测量
QMenu *m;
m = new QMenu(this);
connect(m, &QMenu::triggered, this, [=]
{
connect(m, &QMenu::triggered, this, [=] {
//load data
m_measure_hidden_action->setChecked(Measure::GetHidden());
});
@@ -283,12 +239,9 @@ void QDicomViewer::SetupAnnoTool(QToolButton* annoBtn)
//视窗操作,匿名化
m_patient_hidden_action = m->addAction(tr("Hide patient data"), this, [=] {
if (m_patient_hidden_action->isChecked())
{
if (m_patient_hidden_action->isChecked()) {
AnnoHelper::PrivacyOn();
}
else
{
} else {
AnnoHelper::PrivacyOff();
}
ui->viewContainer->getViewManager()->updateCornerInfoPrivacy();
@@ -298,8 +251,7 @@ void QDicomViewer::SetupAnnoTool(QToolButton* annoBtn)
m->addAction(tr("Show Dicom tags"), this, [&] {
DicomImageView *curV = ui->viewContainer->getCurrentView();
if (curV->hasSeries())
{
if (curV->hasSeries()) {
curV->showMetaData();
}
});
@@ -308,35 +260,80 @@ void QDicomViewer::SetupAnnoTool(QToolButton* annoBtn)
m_measure_hidden_action->setChecked(false);
annoBtn->setPopupMode(QToolButton::MenuButtonPopup);
annoBtn->setMenu(m);
}
namespace {
const int ACTION_COUNT = 7;
const ActionProperty MEASURE_ACTIIONS[ACTION_COUNT] = {
{"Length", ":/InfiniteViewer/Icon/distance.png", AnnotationActorType::RulerAnn},
{"Angle", ":/InfiniteViewer/Icon/angle.png", AnnotationActorType::AngleAnn},
{"Closed polygon", ":/InfiniteViewer/Icon/polygon.png", AnnotationActorType::ClosedPolygonAnn},
{"Open polygon", ":/InfiniteViewer/Icon/polyline.png", AnnotationActorType::OpenPolygonAnn},
{"Arrow", ":/InfiniteViewer/Icon/arrow.png", AnnotationActorType::ArrowAnn},
{"Ellipse", ":/InfiniteViewer/Icon/ellipse.png", AnnotationActorType::EllipseAnn},
{"Text", ":/InfiniteViewer/Icon/text.png", AnnotationActorType::TextAnn}
};
}
//AnnotationActor执行相关
void QDicomViewer::executeActiveMeasure()
{
void QDicomViewer::SetupMeasureTool(QToolButton *measureBtn) {
#define ADD_MEASURE_ACTION(index)\
m->addAction(tr(std::get<0>(MEASURE_ACTIIONS[index])), this, [=] {\
measureBtn->setChecked(true);\
QPixmap map(std::get<1>(MEASURE_ACTIIONS[index]));\
measureBtn->setIcon(QIcon(map));\
MeasureHelper::setMeasureType(std::get<2>(MEASURE_ACTIIONS[index]));\
ui->viewContainer->getViewManager()->activeMeasure();\
})
#define ADD_DEL_ACTION(text, type, func)\
m->addAction(tr(text), this, [=] {\
measureBtn->setChecked(true);\
m_cur_measure = type;\
DicomImageView* curV = ui->viewContainer->getCurrentView();\
if (curV != nullptr)\
{\
curV->func();\
}\
})
measureBtn->setToolTip(QString("Measurements"));
connect(measureBtn, &QToolButton::clicked, this, &QDicomViewer::executeActiveMeasure);
QMenu *m;
m = new QMenu(this);
for (int j = 0; j < ACTION_COUNT; ++j) {
ADD_MEASURE_ACTION(j);
}
m->addSeparator();
ADD_DEL_ACTION("Delete selected", AnnotationActorType::DeleteSelectedAnn, deleteSelectedMeasure);
ADD_DEL_ACTION("Delete all in current slice", AnnotationActorType::DeleteSliceAnn, deleteCurrentSliceMeasure);
ADD_DEL_ACTION("Delete all in current series", AnnotationActorType::DeleteSeriesAnn, deleteCurrentSeriesMeasure);
measureBtn->setPopupMode(QToolButton::MenuButtonPopup);
measureBtn->setMenu(m);
}
void QDicomViewer::executeActiveMeasure() {
ui->viewContainer->getViewManager()->activeMeasure();
DicomImageView *curV = ui->viewContainer->getCurrentView();
switch (MeasureHelper::getMeasureType())
{
switch (MeasureHelper::getMeasureType()) {
case AnnotationActorType::DeleteSelectedAnn:
if (curV != nullptr)
{
if (curV != nullptr) {
curV->deleteSelectedMeasure();
}
break;
case AnnotationActorType::DeleteSliceAnn:
if (curV != nullptr)
{
if (curV != nullptr) {
curV->deleteCurrentSliceMeasure();
}
break;
case AnnotationActorType::DeleteSeriesAnn:
if (curV != nullptr)
{
if (curV != nullptr) {
curV->deleteCurrentSeriesMeasure();
}
break;
@@ -346,110 +343,25 @@ void QDicomViewer::executeActiveMeasure()
}
}
//视窗操作,AnnotationActor新增相关
void QDicomViewer::SetupMeasureTool(QToolButton* measureBtn)
{
measureBtn->setToolTip(QString("Measurements"));
connect(measureBtn, &QToolButton::clicked, this, [=] {
executeActiveMeasure();
});
QMenu* m;
m = new QMenu(this);
m->addAction(tr("Length"), this, [=] {
measureBtn->setChecked(true);
QPixmap map(":/InfiniteViewer/Icon/distance.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::RulerAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addAction(tr("Angle"), this, [=] {
measureBtn->setChecked(true);
QPixmap map(":/InfiniteViewer/Icon/angle.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::AngleAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addAction(tr("Closed polygon"), this, [=] {
measureBtn->setChecked(true);
QPixmap map(":/InfiniteViewer/Icon/polygon.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::ClosedPolygonAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addAction(tr("Open polygon"), this, [=] {
measureBtn->setChecked(true);
QPixmap map(":/InfiniteViewer/Icon/polyline.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::OpenPolygonAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addAction(tr("Arrow"), this, [=] {
measureBtn->setChecked(true);
QPixmap map(":/InfiniteViewer/Icon/arrow.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::ArrowAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addAction(tr("Ellipse"), this, [=] {
QPixmap map(":/InfiniteViewer/Icon/ellipse.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::EllipseAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addAction(tr("Text"), this, [=] {
measureBtn->setChecked(true);
QPixmap map(":/InfiniteViewer/Icon/text.png");
measureBtn->setIcon(QIcon(map));
MeasureHelper::setMeasureType(AnnotationActorType::TextAnn);
ui->viewContainer->getViewManager()->activeMeasure();
});
m->addSeparator();
m->addAction(tr("Delete selected"), this, [=] {
measureBtn->setChecked(true);
m_cur_measure = AnnotationActorType::DeleteSelectedAnn;
//视窗操作,播放相关
void QDicomViewer::SetupCineTool(QToolButton *cineBtn) {
cineBtn->setToolTip(QString("Cine"));
connect(cineBtn, &QToolButton::clicked, this, [&] {
DicomImageView *curV = ui->viewContainer->getCurrentView();
if (curV != nullptr)
{
curV->deleteSelectedMeasure();
if (curV->hasSeries()) {
if (curV->IsCine()) {
curV->setVCRVisible(!curV->isVCRVisible());
} else {
createVCRToolbar(curV);
curV->cineModeOn();
}
});
m->addAction(tr("Delete all in current slice"), this, [=] {
measureBtn->setChecked(true);
m_cur_measure = AnnotationActorType::DeleteSliceAnn;
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr)
{
curV->deleteCurrentSliceMeasure();
}
});
m->addAction(tr("Delete all in current series"), this, [=] {
measureBtn->setChecked(true);
m_cur_measure = AnnotationActorType::DeleteSeriesAnn;
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr)
{
curV->deleteCurrentSeriesMeasure();
}
});
measureBtn->setPopupMode(QToolButton::MenuButtonPopup);
measureBtn->setMenu(m);
}
void QDicomViewer::createVCRToolbar(DicomImageView* v)
{
void QDicomViewer::createVCRToolbar(DicomImageView *v) {
pqVCRToolbar *vcr_toolbar = new pqVCRToolbar(this);
//this->addToolBar(Qt::ToolBarArea::AllToolBarAreas, vcr_toolbar);
vcr_toolbar->setAllowedAreas(Qt::AllToolBarAreas);
@@ -460,62 +372,39 @@ void QDicomViewer::createVCRToolbar(DicomImageView* v)
v->setVCRToolbar(vcr_toolbar);
}
//视窗操作,播放相关
void QDicomViewer::SetupCineTool(QToolButton* cineBtn)
{
cineBtn->setToolTip(QString("Cine"));
connect(cineBtn, &QToolButton::clicked, this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV->hasSeries())
{
if (curV->IsCine())
{
curV->setVCRVisible(!curV->isVCRVisible());
}
else
{
createVCRToolbar(curV);
curV->cineModeOn();
}
}
});
}
//视窗操作fusion相关
void QDicomViewer::SetupFusionTool(QToolButton* fusionBtn)
{
void QDicomViewer::SetupFusionTool(QToolButton *fusionBtn) {
fusionBtn->setToolTip(QString("Fusion"));
connect(fusionBtn, &QToolButton::clicked, ui->viewContainer->getViewManager(), &ImageViewManager::switchFusion);
QMenu* m;
m = new QMenu(this);
QMenu *m = new QMenu(this);
m->addAction(tr("Reset Fusion"), ui->viewContainer->getViewManager(), &ImageViewManager::unloadFusion);
fusionBtn->setPopupMode(QToolButton::MenuButtonPopup);
fusionBtn->setMenu(m);
fusionBtn->setEnabled(false);
connect(ui->viewContainer->getViewManager(),
&ImageViewManager::fusionCheckStateChanged,[=](bool v){
fusionBtn->setEnabled(v);
});
}
//视窗操作slice
void QDicomViewer::SetupSliceTool(QToolButton* sliceBtn)
{
void QDicomViewer::SetupSliceTool(QToolButton *sliceBtn) {
sliceBtn->setToolTip(QString("Browse series"));
connect(sliceBtn, &QToolButton::clicked, this, [&] {
ui->viewContainer->getViewManager()->setInteractionMode(VTKIS_IMAGE_SLICING);
});
}
//视窗操作pan
void QDicomViewer::SetupPanTool(QToolButton* panBtn)
{
void QDicomViewer::SetupPanTool(QToolButton *panBtn) {
panBtn->setToolTip(QString("Pan image"));
connect(panBtn, &QToolButton::clicked, this, [&] {
ui->viewContainer->getViewManager()->setInteractionMode(VTKIS_IMAGE_PAN);
});
}
//视窗操作zoom
void QDicomViewer::SetupZoomTool(QToolButton* zoomBtn)
{
void QDicomViewer::SetupZoomTool(QToolButton *zoomBtn) {
zoomBtn->setToolTip(QString("Zoom image"));
connect(zoomBtn, &QToolButton::clicked, this, [&] {
ui->viewContainer->getViewManager()->setInteractionMode(VTKIS_IMAGE_ZOOM);
@@ -523,17 +412,14 @@ void QDicomViewer::SetupZoomTool(QToolButton* zoomBtn)
}
//视窗操作wwwl
void QDicomViewer::SetupAdjustTool(QToolButton* winlevelBtn)
{
void QDicomViewer::SetupAdjustTool(QToolButton *winlevelBtn) {
winlevelBtn->setToolTip(QString("Adjust window level"));
connect(winlevelBtn, &QToolButton::clicked, this, [&] {
ui->viewContainer->getViewManager()->setInteractionMode(VTKIS_IMAGE_WINDOWLEVEL);
});
// Menu
QMenu* m;
//QAction *a;
m = new QMenu(this);
QMenu *m = new QMenu(this);
m->addAction(tr("Custom Window"), this, [=](bool value) {
winlevelBtn->setChecked(true);
if (nullptr == m_customwin) {
@@ -542,16 +428,13 @@ void QDicomViewer::SetupAdjustTool(QToolButton* winlevelBtn)
m_customwin->setCurrentView(ui->viewContainer->getCurrentView());
//show custom window subwindow
m_customwin->setModal(true);
//m_customwin->show();
m_customwin->exec();
});
m->addAction(tr("Negative"), this, [=](bool value) {
winlevelBtn->setChecked(true);
DicomImageView *curV = ui->viewContainer->getViewManager()->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
if (curV != nullptr && curV->hasSeries()) {
curV->negativeWindow();
}
});
@@ -562,167 +445,113 @@ void QDicomViewer::SetupAdjustTool(QToolButton* winlevelBtn)
}
//视窗操作clear
void QDicomViewer::SetupEmptyTool(QToolButton* emptyBtn)
{
void QDicomViewer::SetupEmptyTool(QToolButton *emptyBtn) {
emptyBtn->setToolTip(QString("Delete current series"));
connect(emptyBtn, &QToolButton::clicked, ui->viewContainer->getCurrentView(), &DicomImageView::viewCleared);
}
//视窗操作flip and rotation
void QDicomViewer::SetupFlipTool(QToolButton* flipBtn)
{
void QDicomViewer::SetupFlipTool(QToolButton *flipBtn) {
flipBtn->setToolTip(QString("Transformations"));
QMenu* m;
m = new QMenu(this);
m->addAction(tr("Rotate 90 CCW"), this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
curV->rotateImage(90, ROTATE_90_CCW);
}
QMenu *m = new QMenu(this);
});
m->addAction(tr("Rotate 90 CW"), this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
curV->rotateImage(-90, ROTATE_90_CW);
}
});
m->addAction(tr("Rotate 180"), this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
curV->rotateImage(180, ROTATE_180);
}
#define ADD_TRANSFORM_ACTION(text,func,...)\
m->addAction(tr(text), this, [&] {\
DicomImageView *curV = ui->viewContainer->getCurrentView();\
if (curV != nullptr && curV->hasSeries()) {\
curV->func(__VA_ARGS__);\
}\
})
});
ADD_TRANSFORM_ACTION("Rotate 90 CCW",rotateImage,90, ROTATE_90_CCW);
ADD_TRANSFORM_ACTION("Rotate 90 CW",rotateImage,-90, ROTATE_90_CW);
ADD_TRANSFORM_ACTION("Rotate 180",rotateImage,180, ROTATE_180);
m->addSeparator();
m->addAction(tr("Flip horizontal"), this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
curV->hFlipImage();
}
});
m->addAction(tr("Flip vertical"), this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
curV->vFlipImage();
}
});
ADD_TRANSFORM_ACTION("Flip horizontal",hFlipImage);
ADD_TRANSFORM_ACTION("Flip vertical",vFlipImage);
m->addSeparator();
m->addAction(tr("Clear transformations"), this, [&] {
DicomImageView* curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
curV->ClearTransformations();
}
});
ADD_TRANSFORM_ACTION("Clear transformations",ClearTransformations);
flipBtn->setPopupMode(QToolButton::MenuButtonPopup);
flipBtn->setMenu(m);
connect(flipBtn, &QPushButton::clicked, this, [&] {
DicomImageView *curV = ui->viewContainer->getCurrentView();
if (curV != nullptr && curV->hasSeries())
{
if (curV != nullptr && curV->hasSeries()) {
curV->rotateImage(90, ROTATE_90_CCW);
}
});
}
//视窗操作sync mode
void QDicomViewer::SetupSyncTool(QToolButton* syncBtn)
{
void QDicomViewer::SetupSyncTool(QToolButton *syncBtn) {
syncBtn->setToolTip(QString("Toggle series synchronization"));
// Menu
QMenu* m;
m = new QMenu(this);
QMenu * m = new QMenu(this);
//QAction *a;
SyncState curst = SyncHelper::getSyncState();
m_sync_state_action = m->addAction(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[curst]), this, [&](bool value) {
m_sync_state_action = m->addAction(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[curst]), this,
[&](bool value) {
});
m_sync_state_action->setCheckable(false);
this->ui->toolBar->addSeparator();
m_sync_item_action[0] = m->addAction(tr("Sychronize slice position"), this, [&](bool value) {
SyncHelper::setSyncItem(SyncItem::SLICE_POS, value);
});
m_sync_item_action[0]->setCheckable(true);
m_sync_item_action[0]->setChecked(false);
m_sync_item_action[0]->setDisabled(true);
#define ADD_SYNC_ITEM(index,text,type)\
m_sync_item_action[index] = m->addAction(tr(text), this, [&](bool value) {\
SyncHelper::setSyncItem(type, value);\
});\
m_sync_item_action[index]->setCheckable(true);\
m_sync_item_action[index]->setChecked(false);\
m_sync_item_action[index]->setDisabled(true);
ADD_SYNC_ITEM(0,"Sychronize slice position",SyncItem::SLICE_POS)
ADD_SYNC_ITEM(1,"Sychronize zoom & pan",SyncItem::ZOOM_PAN)
ADD_SYNC_ITEM(2,"Sychronize window level & width",SyncItem::WIDTH_LEVEL)
m_sync_item_action[1] = m->addAction(tr("Sychronize zoom & pan"), this, [&](bool value) {
SyncHelper::setSyncItem(SyncItem::ZOOM_PAN, value);
});
m_sync_item_action[1]->setCheckable(true);
m_sync_item_action[1]->setChecked(false);
m_sync_item_action[1]->setDisabled(true);
m_sync_item_action[2] = m->addAction(tr("Sychronize window level & width"), this, [&](bool value) {
SyncHelper::setSyncItem(SyncItem::WIDTH_LEVEL, value);
});
m_sync_item_action[2]->setCheckable(true);
m_sync_item_action[2]->setChecked(false);
m_sync_item_action[2]->setDisabled(true);
syncBtn->setPopupMode(QToolButton::MenuButtonPopup);
syncBtn->setMenu(m);
//loop click
connect(syncBtn, &QToolButton::clicked, this, [=] {
SyncState curst = SyncHelper::getSyncState();
connect(syncBtn, &QToolButton::clicked, this,
&QDicomViewer::syncStateChanged);
}
switch (curst)
{
void QDicomViewer::syncStateChanged() const {
QToolButton* syncBtn = qobject_cast<QToolButton*>(sender());
SyncState curst = SyncHelper::getSyncState();
switch (curst) {
case AUTO_SYNC:
syncBtn->setIcon(icon_manual);
m_sync_state_action->setText(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[MANUAL_SYNC]));
SyncHelper::setSyncState(MANUAL_SYNC);
m_sync_item_action[SyncItem::SLICE_POS]->setChecked(SyncHelper::getSyncItem(SyncItem::SLICE_POS));
m_sync_item_action[SyncItem::WIDTH_LEVEL]->setChecked(SyncHelper::getSyncItem(SyncItem::WIDTH_LEVEL));
m_sync_item_action[SyncItem::ZOOM_PAN]->setChecked(SyncHelper::getSyncItem(SyncItem::ZOOM_PAN));
//curst = MANUAL_SYNC;
m_sync_item_action[SLICE_POS]->setChecked(SyncHelper::getSyncItem(SLICE_POS));
m_sync_item_action[WIDTH_LEVEL]->setChecked(SyncHelper::getSyncItem(WIDTH_LEVEL));
m_sync_item_action[ZOOM_PAN]->setChecked(SyncHelper::getSyncItem(ZOOM_PAN));
break;
case MANUAL_SYNC:
syncBtn->setIcon(icon_dis);
m_sync_state_action->setText(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[DIS_SYNC]));
SyncHelper::setSyncState(DIS_SYNC);
for (int i = 0; i < SYNC_ITEM_NUM; i++)
{
for (int i = 0; i < SYNC_ITEM_NUM; i++) {
m_sync_item_action[i]->setChecked(false);
m_sync_item_action[i]->setDisabled(true);
}
//curst = DIS_SYNC;
break;
case DIS_SYNC:
syncBtn->setIcon(icon_auto);
m_sync_state_action->setText(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[AUTO_SYNC]));
SyncHelper::setSyncState(AUTO_SYNC);
for (int i = 0; i < SYNC_ITEM_NUM; i++)
{
for (int i = 0; i < SYNC_ITEM_NUM; i++) {
m_sync_item_action[i]->setDisabled(false);
}
m_sync_item_action[SyncItem::SLICE_POS]->setChecked(SyncHelper::getSyncItem(SyncItem::SLICE_POS));
m_sync_item_action[SyncItem::WIDTH_LEVEL]->setChecked(SyncHelper::getSyncItem(SyncItem::WIDTH_LEVEL));
m_sync_item_action[SyncItem::ZOOM_PAN]->setChecked(SyncHelper::getSyncItem(SyncItem::ZOOM_PAN));
//curst = AUTO_SYNC;
m_sync_item_action[SLICE_POS]->setChecked(SyncHelper::getSyncItem(SLICE_POS));
m_sync_item_action[WIDTH_LEVEL]->setChecked(SyncHelper::getSyncItem(WIDTH_LEVEL));
m_sync_item_action[ZOOM_PAN]->setChecked(SyncHelper::getSyncItem(ZOOM_PAN));
break;
default:
break;
}
});
}
//视窗操作file open相关
@@ -732,10 +561,11 @@ void QDicomViewer::SetupFileTool(QToolButton* fileBtn) {
QMenu *m;
m = new QMenu(this);
m->addAction(tr("Open DICOM folder"), this, [&] {
QString p = QFileDialog::getExistingDirectory(this, tr("Open dicom directory"), m_qs.value("DIR_PATH_ID").toString());
QString p = QFileDialog::getExistingDirectory(this, tr("Open dicom directory"),
m_qs.value("DIR_PATH_ID").toString());
if (!p.isEmpty()) {
m_qs.setValue("DIR_PATH_ID", p);
openAndDrawDICOM(p.toLocal8Bit().toStdString(), DIR_OPEN_MODE);
openDICOM(p.toLocal8Bit().toStdString(), DIR_OPEN_MODE);
}
});
@@ -745,14 +575,10 @@ void QDicomViewer::SetupFileTool(QToolButton* fileBtn) {
QString fn = QFileDialog::getOpenFileName(this, tr("Open dicom files"), m_qs.value("FILE_PATH_ID").toString());
if (!fn.isEmpty()) {
m_qs.setValue("FILE_PATH_ID", fn);
openAndDrawDICOM(fn.toLocal8Bit().toStdString(), FILE_OPEN_MODE);
openDICOM(fn.toLocal8Bit().toStdString(), FILE_OPEN_MODE);
}
});
m->addAction(tr("Close all"), this, [&] {
//ui->thumbnailBar_->clear();
});
m->addSeparator();
m->addAction(tr("Quit"), this, &QDicomViewer::close);
fileBtn->setPopupMode(QToolButton::MenuButtonPopup);
@@ -760,19 +586,16 @@ void QDicomViewer::SetupFileTool(QToolButton* fileBtn) {
// connect
connect(fileBtn, &QToolButton::clicked, this, [&] {
//QSettings s;
//QString p = s.value(DIR_PATH_ID, ".").toString();
QString p = QFileDialog::getExistingDirectory(this, tr("Open dicom directory"), m_qs.value("DIR_PATH_ID").toString());
QString p = QFileDialog::getExistingDirectory(this, tr("Open dicom directory"),
m_qs.value("DIR_PATH_ID").toString());
if (!p.isEmpty()) {
m_qs.setValue("DIR_PATH_ID", p);
//ui->thumbnailBar_->setImagePaths(QStringList() << p);
openAndDrawDICOM(p.toLocal8Bit().toStdString(), DIR_OPEN_MODE);
openDICOM(p.toLocal8Bit().toStdString(), DIR_OPEN_MODE);
}
});
}
void QDicomViewer::SetupImportTool(QToolButton* importBtn)
{
void QDicomViewer::SetupImportTool(QToolButton *importBtn) {
importBtn->setToolTip(QString("Search and download studies from PACS locations"));
connect(importBtn, &QToolButton::clicked, this, [&] {
if (nullptr == m_import) {
@@ -781,12 +604,9 @@ void QDicomViewer::SetupImportTool(QToolButton* importBtn)
}
m_import->show();
});
}
void QDicomViewer::SetupExportTool(QToolButton* saveBtn)
{
void QDicomViewer::SetupExportTool(QToolButton *saveBtn) {
saveBtn->setToolTip(QString("Export images"));
connect(saveBtn, &QToolButton::clicked, this, [=] {
if (nullptr == exportDialog) {
@@ -800,8 +620,7 @@ void QDicomViewer::SetupExportTool(QToolButton* saveBtn)
});
}
void QDicomViewer::displayThumbnailBar(bool value)
{
void QDicomViewer::displayThumbnailBar(bool value) {
VCRHelper::setThumbnailbar(value);
ui->thumbnailBar->setVisible(value);
m_preview_display_action->setChecked(value);
@@ -834,8 +653,7 @@ void QDicomViewer::SetupGridTool(QToolButton* gridBtn) {
});
}
void QDicomViewer::SetupConnections()
{
void QDicomViewer::SetupConnections() {
//通知左侧的缩略图bar 当前选中series的变换
connect(ui->viewContainer, &ViewContainerWidget::onThumbnailTrigger,
ui->thumbnailBar, &ThumbnailBarWidget::Slot_setCurrentThumbnail);
@@ -847,36 +665,23 @@ void QDicomViewer::SetupConnections()
connect(ui->toolBar, &QToolBar::visibilityChanged,
this, &QDicomViewer::Slot_ToolbarVisibilityChanged);
//connect(ui->viewContainer, SIGNAL(onThumbnailTrigger(DicomImageView*)),
// ui->vcr_toolbar, SLOT(setImageView(DicomImageView*)));
//connect(ui->thumbnailBar, SIGNAL(Signal_CopyDicomView(SeriesInfo_t*)),
// this, SLOT(Slot_CopyDicomView(SeriesInfo_t*)));
}
void QDicomViewer::Slot_ToolbarVisibilityChanged(bool visible)
{
void QDicomViewer::Slot_ToolbarVisibilityChanged(bool visible) {
VCRHelper::setToolbar(visible);
}
void QDicomViewer::openDICOMFromPACS(int err, std::string dirName)
{
void QDicomViewer::openDICOMFromPACS(int err, std::string dirName) {
if (err == NOERROR) {
openAndDrawDICOM(dirName, DIR_OPEN_MODE);
}
else
{
openDICOM(dirName, DIR_OPEN_MODE);
} else {
//pop out msg box
QMessageBox::warning(this, "Warning", "open DICOM Images From PACS Fail");
}
}
//TODO: 覆盖逻辑和增加逻辑待补充
void QDicomViewer::openAndDrawDICOM(const std::string& dicomName, SeriesOpenMode openMode) {
void QDicomViewer::openDICOM(const std::string &dicomName, SeriesOpenMode openMode) {
displayThumbnailBar(true);
@@ -889,10 +694,7 @@ void QDicomViewer::openAndDrawDICOM(const std::string& dicomName, SeriesOpenMode
auto unique = helper->getDefaultUniqueID();
ui->viewContainer->getViewManager()->viewReload(unique);
//view clicked will notify thumbnailbar update
ui->thumbnailBar->updateThumbnailBar();
}

View File

@@ -7,6 +7,8 @@
#include "customwindow.h"
#include "UI/Widget/Measure/pqFontPropertyWidget.h"
typedef tuple<const char *, const char *, int> ActionProperty;
/**
* @brief 主窗口Class
* 继承自QMainWindow,主要用于显示整个界面
@@ -82,7 +84,7 @@ private:
* @param dicomName DICOM文件路径
* @param openMode 文件打开方式,文件方式或文件夹方式
*/
void openAndDrawDICOM(const std::string &dicomName, SeriesOpenMode openMode);
void openDICOM(const std::string &dicomName, SeriesOpenMode openMode);
/**
* 设置部分空间的槽函数连接
@@ -121,4 +123,5 @@ private:
AnnotationActorType m_cur_measure = AnnotationActorType::RulerAnn;
void syncStateChanged() const;
};