def init_ui(self): hlayout = QHBoxLayout() self.settings_functions_stacked_widget = SettingsFunctionsStackedWidget( ) settings_content_splitter = QSplitter(Qt.Horizontal) table_info_splitter = QSplitter(Qt.Vertical) self.table_tab_widget = TableTabWidget() self.info_stacked_widget = InfoStackedWidget() table_info_splitter.addWidget(self.table_tab_widget) table_info_splitter.addWidget(self.info_stacked_widget) # The two numbers 20000 and 10000 indicate the relative sizes of the two child widgets. # The numbers are purposely set very big instead of 2 and 1. # See https://stackoverflow.com/questions/29560912/qsplitter-stretching-factors-behave-differnt-from-normal-ones for reference table_info_splitter.setSizes([20000, 10000]) settings_content_splitter.addWidget( self.settings_functions_stacked_widget) settings_content_splitter.addWidget(table_info_splitter) settings_content_splitter.setSizes([10000, 40000]) hlayout.addWidget(settings_content_splitter) self.setLayout(hlayout) self.settings_functions_stacked_widget.setFrameShape( QFrame.StyledPanel) self.info_stacked_widget.setFrameShape(QFrame.StyledPanel)
def __init__(self, parent=None): super().__init__(parent) self.editor = PythonEditor(self) self.resize(650, 500) fileMenu = QMenu(self.tr("&File"), self) fileMenu.addAction(self.tr("&New…"), self.newFile, QKeySequence.New) fileMenu.addAction(self.tr("&Open…"), self.openFile, QKeySequence.Open) fileMenu.addAction(self.tr("&Save"), self.saveFile, QKeySequence.Save) fileMenu.addAction(self.tr("Save &As…"), self.saveFileAs, QKeySequence.SaveAs) fileMenu.addSeparator() fileMenu.addAction(self.tr("&Run…"), self.runScript, "Ctrl+R") fileMenu.addSeparator() fileMenu.addAction(self.tr("&Close"), self.close, platformSpecific.closeKeySequence()) self.menuBar().addMenu(fileMenu) self.fileChooser = FileChooser(self) self.fileChooser.fileOpened.connect(self.openFile) splitter = QSplitter(self) splitter.addWidget(self.fileChooser) splitter.addWidget(self.editor) splitter.setStretchFactor(0, 2) splitter.setStretchFactor(1, 5) splitter.setSizes([0, 1]) self.setCentralWidget(splitter) self.newFile() self.editor.modificationChanged.connect(self.setWindowModified)
def InitWindow(self): self.setWindowIcon(QtGui.QIcon(self.IconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.setStyleSheet('background-color:yellow') hbox = QHBoxLayout() leftFrame = QFrame() leftFrame.setFrameShape(QFrame.StyledPanel) bottomFrame = QFrame() bottomFrame.setFrameShape(QFrame.StyledPanel) splitterOne = QSplitter(Qt.Horizontal) lineEdit = QLineEdit() splitterOne.addWidget(leftFrame) splitterOne.addWidget(lineEdit) splitterOne.setSizes([200, 200]) splitterTwo = QSplitter(Qt.Vertical) lineEdit = QLineEdit() splitterTwo.addWidget(splitterOne) splitterTwo.addWidget(bottomFrame) splitterTwo.setSizes([200, 200]) hbox.addWidget(splitterTwo) self.setLayout(hbox) self.show()
def __init__(self): super().__init__() self.title = "PyQt5 Splitter" self.top = 200 self.left = 500 self.width = 400 self.height = 400 hbox = QHBoxLayout() left = QFrame() left.setFrameShape(QFrame.StyledPanel) bottom = QFrame() bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) splitter1.setStyleSheet('background-color:red') lineedit = QLineEdit() lineedit.setStyleSheet('background-color:green') splitter1.addWidget(left) splitter1.addWidget(lineedit) splitter1.setSizes([300, 400]) spliiter2 = QSplitter(Qt.Vertical) spliiter2.addWidget(splitter1) spliiter2.addWidget(bottom) spliiter2.setStyleSheet('background-color:yellow') hbox.addWidget(spliiter2) self.setLayout(hbox) self.setWindowIcon(QtGui.QIcon("avatar.png")) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.show()
def make_main_dashboard(self, width: int, height: int) -> QHBoxLayout: # Make the right panel, which hosts the metronome and tuner top_right = QFrame() top_right.setFrameShape(QFrame.StyledPanel) bottom_right = QFrame() bottom_right.setFrameShape(QFrame.StyledPanel) right_side = QSplitter(Qt.Vertical) right_side.addWidget(top_right) right_side.addWidget(bottom_right) right_side.setSizes([height / 2, height / 2]) # Make the left panel, which hosts the progress tracking functionality left_side = QFrame() left_side.setFrameShape(QFrame.StyledPanel) # Put a splitter between the two sides tiles = QSplitter(Qt.Horizontal) tiles.addWidget(left_side) tiles.addWidget(right_side) tiles.setSizes([width / 2, width / 2]) # Add the windows view to the app dashboard = QHBoxLayout(self) dashboard.addWidget(tiles) return dashboard
def initUI(self): hbox = QHBoxLayout(self) topleft = QFrame() topleft.setFrameShape(QFrame.StyledPanel) bottom = QFrame() bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) textedit = QTextEdit() splitter1.addWidget(topleft) splitter1.addWidget(textedit) splitter1.setSizes([100, 200]) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) QApplication.setStyle(QStyleFactory.create('Cleanlooks')) self.setGeometry(300, 300, 300, 200) self.setWindowTitle('QSplitter demo') self.show()
def __init__(self,conn,**kwparms): #holder=None,script=None,parent=None): super(QueryTab,self).__init__(kwparms.get('parent',None)) self.limit = 1000 self.conn = conn self.connClose = kwparms.get('connClose',False) self.holder = kwparms.get('holder',None) self.script = kwparms.get('script',None) self.fileName = None self.browser = QTableView() self.baseModel = None self.sqlEdit = QTextEdit() self.msgLine = QTextEdit() self.msgLine.setReadOnly(True) self.msgLine.setText("Bienvenido al query masta") split = QSplitter(Qt.Vertical) split.addWidget(self.sqlEdit) split.addWidget(self.browser) split.addWidget(self.msgLine) split.setSizes([50,250,25]) #split.setRubberBand(1) if self.script: self.sqlEdit.setText(queryFormat(self.script)) self.sqlEdit.hide() meatLayout = QVBoxLayout() meatLayout.addWidget(split) self.setLayout(meatLayout)
def init_window(self): self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QHBoxLayout() left = QFrame() left.setFrameShape(QFrame.StyledPanel) # left.setStyleSheet("background-color:violet") bottom = QFrame() bottom.setFrameShape(QFrame.StyledPanel) # bottom.setStyleSheet("background-color:brown") line_edit = QLineEdit() line_edit.setStyleSheet("background-color:orange") splitter1 = QSplitter(Qt.Horizontal) splitter1.setStyleSheet("background-color:violet") splitter1.addWidget(left) splitter1.addWidget(line_edit) splitter1.setSizes([200, 200]) splitter2 = QSplitter(Qt.Vertical) splitter2.setStyleSheet("background-color:brown") splitter2.addWidget(splitter1) splitter2.addWidget(bottom) hbox.addWidget(splitter2) self.setLayout(hbox) self.show()
def __init__(self, param, win, parent=None): super().__init__(parent) self.param = param self.ParamTableWiget = ParamTableWiget(param, self) self.Report = QTextEdit(self) font = QFont() font.setPointSize(12) self.Report.setFont(font) win.setParamTable(self.ParamTableWiget, self.Report) hbox = QHBoxLayout() #vbox = QVBoxLayout() splitterH = QSplitter(Qt.Horizontal) splitterH.addWidget(self.ParamTableWiget) splitterH.addWidget(self.Report) #splitterH.scroll(200,500) splitterH.setSizes([300, 500]) sp = splitterH.sizePolicy() sp.setVerticalPolicy(QSizePolicy.Expanding) splitterH.setSizePolicy(sp) #hbox = QHBoxLayout() # vbox.addStretch(1) hbox.addWidget(splitterH) #bCalc = QPushButton('Расчет', self) #bCalc.clicked[bool].connect(self.Calc) #vbox.addWidget(self.ParamTableWiget) #vbox.addWidget(bCalc) #hbox.addLayout(vbox) #hbox.addWidget(self.Report) self.setLayout(hbox) self.Calc()
def __init__(self): # multiple inheritance super().__init__() # creating widgets for chatBody layout which uses splitter2 to combine the Send Button and splitter; splitter combines Chat History and Chat Text Field self.chatTextField = QLineEdit(self) self.chatTextField.resize(480, 100) self.chatTextField.move(10, 350) self.btnSend = QPushButton("Send", self) self.btnSend.resize(480, 30) self.btnSendFont = self.btnSend.font() self.btnSendFont.setPointSize(15) self.btnSend.setFont(self.btnSendFont) self.btnSend.move(10, 460) self.btnSend.setStyleSheet("background-color: #86f715") self.btnSend.clicked.connect(self.send) self.chat = QTextEdit() self.chat.setReadOnly(True) splitter = QSplitter(QtCore.Qt.Vertical) splitter.addWidget(self.chat) splitter.addWidget(self.chatTextField) splitter.setSizes([400, 100]) splitter2 = QSplitter(QtCore.Qt.Vertical) splitter2.addWidget(splitter) splitter2.addWidget(self.btnSend) splitter2.setSizes([200, 10]) self.chatBody = QVBoxLayout(self) self.chatBody.addWidget(splitter2) self.setWindowTitle("Chat Application") self.resize(500, 500)
def init_UI(self): # Centers window to provide consistent launch of app self.statusBar().showMessage('Ready') self.setWindowTitle('PMR Insight Collective Knowledge') self.setWindowIcon( QIcon('../Source/Backend/Resources/Images/logo_small.png')) self.resize(1900, 1030) frame = self.frameGeometry() center_point = QDesktopWidget().availableGeometry().center() frame.moveCenter(center_point) self.move(frame.topLeft()) self.init_toolbar() splitV = QSplitter(Qt.Vertical) splitV.addWidget(self.vectors) splitV.addWidget(NodeTableFrame()) splitV.setStretchFactor(1, 1) splitV.setSizes([600, 900]) self.layout.addWidget(splitV) self.setCentralWidget(QWidget(self)) self.centralWidget().setLayout(self.layout) self.show()
def __init__(self): super().__init__() self.flag = 0 self.chatTextField = QLineEdit(self) self.chatTextField.resize(480, 100) self.chatTextField.move(10, 350) self.btnSend = QPushButton("Send", self) self.btnSend.resize(480, 30) self.btnSendFont = self.btnSend.font() self.btnSendFont.setPointSize(15) self.btnSend.setFont(self.btnSendFont) self.btnSend.move(10, 460) self.btnSend.setStyleSheet("background-color: #F7CE16") self.btnSend.clicked.connect(self.send) self.chatBody = QVBoxLayout(self) splitter = QSplitter(QtCore.Qt.Vertical) self.chat = QTextEdit() self.chat.setReadOnly(True) splitter.addWidget(self.chat) splitter.addWidget(self.chatTextField) splitter.setSizes([400, 100]) splitter2 = QSplitter(QtCore.Qt.Vertical) splitter2.addWidget(splitter) splitter2.addWidget(self.btnSend) splitter2.setSizes([200, 10]) self.chatBody.addWidget(splitter2) self.setWindowTitle("Chat Application") self.resize(500, 500)
def initUI(self): hbox = QHBoxLayout(self) f1 = QFrame(self) f1.setFrameShape(QFrame.StyledPanel) f1.setStyleSheet("QFrame {background-color:red}") f2 = QFrame(self) f2.setFrameShape(QFrame.StyledPanel) f2.setStyleSheet("QFrame {background-color:blue}") f3 = QFrame(self) f3.setFrameShape(QFrame.StyledPanel) f3.setStyleSheet("QFrame {background-color:yellow}") splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(f1) splitter1.addWidget(f2) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(f3) splitter2.setSizes([150, 150]) hbox.addWidget(splitter2) self.setLayout(hbox) self.setGeometry(300, 300, 300, 350) self.setWindowTitle('Q-splitter') self.show()
def __init__(self, parent=None): super(MainForm, self).__init__(parent) self.model = WaterQualityModel( os.path.join(os.path.dirname(__file__), "waterdata.csv.gz")) self.tableView = QTableView() self.tableView.setAlternatingRowColors(True) self.tableView.setModel(self.model) self.waterView = WaterQualityView() self.waterView.setModel(self.model) scrollArea = QScrollArea() scrollArea.setBackgroundRole(QPalette.Light) scrollArea.setWidget(self.waterView) self.waterView.scrollarea = scrollArea splitter = QSplitter(Qt.Horizontal) splitter.addWidget(self.tableView) splitter.addWidget(scrollArea) splitter.setSizes([600, 250]) layout = QHBoxLayout() layout.addWidget(splitter) self.setLayout(layout) self.setWindowTitle("Water Quality Data") QTimer.singleShot(0, self.initialLoad)
def initUI(self): """Override.""" self._monitor_tb.setTabPosition(QTabWidget.TabPosition.South) self._monitor_tb.addTab(self._avail_src_view, "Available sources") self._monitor_tb.addTab(self._process_mon_view, "Process monitor") splitter = QSplitter(Qt.Vertical) splitter.setHandleWidth(self.SPLITTER_HANDLE_WIDTH) splitter.setChildrenCollapsible(False) splitter.addWidget(self._con_view) splitter.addWidget(self._src_view) splitter.addWidget(self._monitor_tb) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 1) h = splitter.sizeHint().height() splitter.setSizes([0.1 * h, 0.6 * h, 0.3 * h]) layout = QVBoxLayout() layout.addWidget(splitter) self.setLayout(layout) self._con_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self._src_view.expandToDepth(1) self._src_view.resizeColumnToContents(0) self._src_view.resizeColumnToContents(1)
def init_ui(self): hbox = QHBoxLayout(self) # Left frame for map left = QFrame(self) left.setFrameShape(QFrame.StyledPanel) # Right frame for control tabs right = QFrame(self) right.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(left) splitter1.addWidget(right) splitter1.setSizes([100, 70]) hbox.addWidget(splitter1) self.setLayout(hbox) # Create map widget in left split map_layout = QHBoxLayout(left) map_widget = MapWidget(self, self.__game_engine) map_layout.addWidget(map_widget) left.setLayout(map_layout) # Create control widget in right split control_layout = QHBoxLayout(right) control_widget = ControlWidget(right, self.__game_engine) control_layout.addWidget(control_widget) right.setLayout(control_layout)
def __init__(self, parent=None): super(QMainWindow,self).__init__() #--------------------------------------------------------------- statusWin = QLabel(self) #statusWin = QPlainTextEdit(self) # status window #statusWin.appendHtml("<b>hallo<br>hallo2<br>hallo3</b>") tabWin = TabWidgets(self) # tabbed window print('hint status win: {0}'.format(statusWin.sizeHint())) print('hint_tab win: {0}'.format(tabWin.sizeHint())) print('hint main win: {0}'.format(self.sizeHint())) mSize = QFontMetrics(statusWin.font()) rowHt = mSize.lineSpacing() # fixed height for statusWin needed as the sizeHint of tabWin is very small #statusWin.setFixedHeight(4*rowHt+4) # add status window underneath plot Tab Widgets: spltVMain = QSplitter(QtCore.Qt.Vertical) spltVMain.addWidget(tabWin) spltVMain.addWidget(statusWin) # relative initial sizes of subwidgets, this doesn't work here # spltVMain.setStretchFactor(4,1) spltVMain.setSizes([statusWin.sizeHint().height()*2, statusWin.sizeHint().height()*0.05]) spltVMain.setFocus() # make spltVMain occupy the main area of QMainWindow and set inheritance self.setCentralWidget(spltVMain) print('size tabs: {0}'.format(tabWin.size())) print('size status: {0}'.format(statusWin.size())) print('size self: {0}'.format(self.size()))
class AppearanceWindow(QWidget): """ This is the appearance window letting the user customise the appearance of the app. """ def __init__(self, parent: QWidget): super().__init__(parent) self.setWindowFlags(Qt.Tool | Qt.Dialog) self.setWindowModality(Qt.WindowModal) self.setWindowTitle("Settings") self.resize(size_from_percentage_of_screen(0.7, 0.7)) centre_on_screen(self) self.close_shortcut = QShortcut(QKeySequence("Esc"), self) # noinspection PyUnresolvedReferences self.close_shortcut.activated.connect(self.cancel_clicked) self.ok_button = QPushButton(self) self.ok_button.setText("OK") self.ok_button.clicked.connect(self.ok_clicked) self.cancel_button = QPushButton(self) self.cancel_button.setText("Cancel") self.cancel_button.clicked.connect(self.cancel_clicked) self.apply_button = QPushButton(self) self.apply_button.setText("Apply") self.apply_button.clicked.connect(self.apply_clicked) horizontal_layout = QHBoxLayout() horizontal_layout.addStretch(1) horizontal_layout.addWidget(self.ok_button) horizontal_layout.addWidget(self.cancel_button) horizontal_layout.addWidget(self.apply_button) self.vertical_splitter = QSplitter(Qt.Horizontal) self.vertical_splitter.setSizes([100000, 400000]) vertical_layout = QVBoxLayout() vertical_layout.addWidget(self.vertical_splitter) vertical_layout.addLayout(horizontal_layout) self.setLayout(vertical_layout) user_settings().restore_widget(self, Key.appearance) @pyqtSlot() def ok_clicked(self): self.close() @pyqtSlot() def cancel_clicked(self): self.close() @pyqtSlot() def apply_clicked(self): self.close() def closeEvent(self, event: QCloseEvent): user_settings().save_widget(self, Key.appearance) super().closeEvent(event)
def initUI(self): """Override.""" ctrl_widget = QWidget() ctrl_layout = QHBoxLayout() AT = Qt.AlignTop ctrl_layout.addWidget(self._roi_ctrl_widget) ctrl_layout.addWidget(self._roi_fom_ctrl_widget, alignment=AT) ctrl_layout.addWidget(self._roi_hist_ctrl_widget, alignment=AT) ctrl_layout.addWidget(self._roi_norm_ctrl_widget, alignment=AT) ctrl_layout.addWidget(self._roi_proj_ctrl_widget, alignment=AT) ctrl_layout.setContentsMargins(1, 1, 1, 1) ctrl_widget.setLayout(ctrl_layout) ctrl_widget.setFixedHeight( self._roi_proj_ctrl_widget.minimumSizeHint().height()) subview_splitter = QSplitter(Qt.Vertical) subview_splitter.setHandleWidth(9) subview_splitter.setChildrenCollapsible(False) subview_splitter.addWidget(self._roi_proj_plot) subview_splitter.addWidget(self._roi_hist) view_splitter = QSplitter(Qt.Horizontal) view_splitter.setHandleWidth(9) view_splitter.setChildrenCollapsible(False) view_splitter.addWidget(self._corrected) view_splitter.addWidget(subview_splitter) view_splitter.setSizes([1e6, 1e6]) layout = QVBoxLayout() layout.addWidget(view_splitter) layout.addWidget(ctrl_widget) layout.setContentsMargins(1, 1, 1, 1) self.setLayout(layout)
class MyMainWindow(QWidget): def __init__(self): super().__init__() self.title = "PyQt5 Splitter" self.top = 200 self.left = 500 self.width = 400 self.height = 300 hbox = QHBoxLayout() self.widg_1 = QFrame() self.widg_1.setFrameShape(QFrame.StyledPanel) self.my_splitter = QSplitter(Qt.Horizontal) self.widg_2 = QLineEdit() self.my_splitter.addWidget(self.widg_1) self.my_splitter.addWidget(self.widg_2) self.my_splitter.setSizes([200, 200]) hbox.addWidget(self.my_splitter) # Note: splitter handle 0 is always hidden and handle 1 is between the widgets 1 & 2 self.my_splitter_handle = self.my_splitter.handle(1) self.my_splitter.setStyleSheet( "QSplitter::handle {background: 3px blue};") self.setLayout(hbox) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) self.show()
def setup_center_ui(self): """ Set up the central widget area, which includes: DatasetWidget LogWidget """ self.setWindowTitle(f"CLARITE v{self.appctx.VERSION}") self.setWindowIcon(QIcon(":/images/clarite_logo.png")) self.setContentsMargins(10, 10, 10, 10) # Set up the central widget splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.setMinimumSize(800, 600) self.setCentralWidget(splitter) # Add the main sections dataset_widget = DatasetWidget(parent=self) splitter.addWidget(dataset_widget) self.log_tabs = QTabWidget(parent=self) self.log_tabs.setTabPosition(QTabWidget.North) splitter.addWidget(self.log_tabs) # Set the initial sizes (and relative ratio) of the two groups splitter.setSizes([500, 100])
def initUI(self): """Override.""" right_panel = QTabWidget() right_panel1 = QSplitter(Qt.Vertical) right_panel1.addWidget(self._xgm) right_panel1.addWidget(self._digitizer) right_panel1.addWidget(self._scan) right_panel2 = QSplitter(Qt.Horizontal) correlation_panel = QSplitter(Qt.Vertical) for w in self._correlations: correlation_panel.addWidget(w) spectra_panel = QSplitter(Qt.Vertical) spectra_panel.addWidget(self._pn_spectra) spectra_panel.addWidget(self._xas_xmcd_spectra) spectra_panel.addWidget(self._i0_spectrum) right_panel2.addWidget(correlation_panel) right_panel2.addWidget(spectra_panel) right_panel2.setSizes([100, 200]) right_panel.addTab(right_panel1, "Raw data") right_panel.addTab(right_panel2, "Correlation and spectra") right_panel.setTabPosition(QTabWidget.TabPosition.South) cw = self.centralWidget() cw.addWidget(right_panel) cw.setSizes([self._TOTAL_W / 4, 3 * self._TOTAL_W / 4]) self.resize(self._TOTAL_W, self._TOTAL_H)
def sig_to_stems_clicked(self, row): signature = self.sig_to_stems_major_table.item(row, 0).text() print(signature) signature = tuple(signature.split(SEP_SIG)) stems = sorted(self.lexicon.signatures_to_stems()[signature]) number_of_stems_per_column = 5 # create a master list of sublists, where each sublist contains k stems # k = number_of_stems_per_column stem_rows = list() stem_row = list() for i, stem in enumerate(stems, 1): stem_row.append(stem) if not i % number_of_stems_per_column: stem_rows.append(stem_row) stem_row = list() if stem_row: stem_rows.append(stem_row) # set up the minor table as table widget sig_to_stems_minor_table = QTableWidget() sig_to_stems_minor_table.horizontalHeader().hide() sig_to_stems_minor_table.verticalHeader().hide() sig_to_stems_minor_table.clear() sig_to_stems_minor_table.setRowCount(len(stem_rows)) sig_to_stems_minor_table.setColumnCount(number_of_stems_per_column) # fill in the minor table for row, stem_row in enumerate(stem_rows): for col, stem in enumerate(stem_row): item = QTableWidgetItem(stem) sig_to_stems_minor_table.setItem(row, col, item) sig_to_stems_minor_table.resizeColumnsToContents() minor_table_title = QLabel('{} (number of stems: {})' .format(SEP_SIG.join(signature), len(stems)) ) minor_table_widget_with_title = QWidget() layout = QVBoxLayout() layout.addWidget(minor_table_title) layout.addWidget(sig_to_stems_minor_table) minor_table_widget_with_title.setLayout(layout) new_display = QSplitter(Qt.Horizontal) new_display.setHandleWidth(10) new_display.setChildrenCollapsible(False) new_display.addWidget(self.sig_to_stems_major_table) new_display.addWidget(minor_table_widget_with_title) new_display_width = self.majorDisplay.width() / 2 new_display.setSizes( [new_display_width * 0.4, new_display_width * 0.6]) self.load_main_window(major_display=new_display) self.status.clearMessage() self.status.showMessage('{} selected'.format(signature))
def InitWindow(self): self.setWindowIcon(QtGui.QIcon(self.iconName)) self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) hbox = QHBoxLayout() left = QFrame() left.setFrameShape(QFrame.StyledPanel) bottom = QFrame() bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter(Qt.Horizontal) lineedit = QLineEdit() lineedit.setStyleSheet('background-color:green') splitter1.addWidget(left) splitter1.addWidget(lineedit) splitter1.setSizes([200, 200]) splitter1.setStyleSheet('background-color:red') splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(bottom) splitter2.setStyleSheet('background-color:yellow') hbox.addWidget(splitter2) self.setLayout(hbox) self.show()
def sig_to_stems_clicked(self, row): signature = self.sig_to_stems_major_table.item(row, 0).text() print(signature) signature = tuple(signature.split(SEP_SIG)) stems = sorted(self.lexicon.signatures_to_stems()[signature]) number_of_stems_per_column = 5 # create a master list of sublists, where each sublist contains k stems # k = number_of_stems_per_column stem_rows = list() stem_row = list() for i, stem in enumerate(stems, 1): stem_row.append(stem) if not i % number_of_stems_per_column: stem_rows.append(stem_row) stem_row = list() if stem_row: stem_rows.append(stem_row) # set up the minor table as table widget sig_to_stems_minor_table = QTableWidget() sig_to_stems_minor_table.horizontalHeader().hide() sig_to_stems_minor_table.verticalHeader().hide() sig_to_stems_minor_table.clear() sig_to_stems_minor_table.setRowCount(len(stem_rows)) sig_to_stems_minor_table.setColumnCount(number_of_stems_per_column) # fill in the minor table for row, stem_row in enumerate(stem_rows): for col, stem in enumerate(stem_row): item = QTableWidgetItem(stem) sig_to_stems_minor_table.setItem(row, col, item) sig_to_stems_minor_table.resizeColumnsToContents() minor_table_title = QLabel('{} (number of stems: {})' .format(SEP_SIG.join(signature), len(stems))) minor_table_widget_with_title = QWidget() layout = QVBoxLayout() layout.addWidget(minor_table_title) layout.addWidget(sig_to_stems_minor_table) minor_table_widget_with_title.setLayout(layout) new_display = QSplitter(Qt.Horizontal) new_display.setHandleWidth(10) new_display.setChildrenCollapsible(False) new_display.addWidget(self.sig_to_stems_major_table) new_display.addWidget(minor_table_widget_with_title) new_display_width = self.majorDisplay.width() / 2 new_display.setSizes( [new_display_width * 0.4, new_display_width * 0.6]) self.load_main_window(major_display=new_display) self.status.clearMessage() self.status.showMessage('{} selected'.format(signature))
def __init__(self): super().__init__() uids = get_all_uids() layout = QHBoxLayout() main_splitter = QSplitter(self) image_splitter = QSplitter(QtCore.Qt.Vertical, self) picture_viewer = PictureViewer(image_splitter) meta_viewer = MetaViewer(image_splitter) atexit.register(lambda: meta_viewer.save_meta()) picture_frame = QWidget(main_splitter) picture_frame.setLayout(layout) scrollbar = QScrollBar(QtCore.Qt.Vertical) image_pane = PictureGrid(picture_frame, uids, scrollbar, picture_viewer, meta_viewer) layout.addWidget(image_pane) layout.addWidget(scrollbar) image_splitter.addWidget(picture_viewer) image_splitter.addWidget(meta_viewer) image_splitter.setSizes([600, 200]) main_splitter.addWidget(picture_frame) main_splitter.addWidget(image_splitter) main_splitter.setSizes([300, 200]) # TODO What do these numbers do? self.setCentralWidget(main_splitter) self.setWindowTitle("Cutespam") menu = self.menuBar() file = menu.addMenu("File") file.addAction("Import") search = TagLineEdit(self) search.setFixedWidth(400) completer = QCompleter([], search) search.setMultipleCompleter(completer) search_container = QWidget() layout = QVBoxLayout(search_container) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(search) menu.setCornerWidget(search_container) def on_typed(): words = search.text().split(" ") if len(search.text()) == 0: image_pane.uids = get_all_uids() else: image_pane.uids = list(get_uids_from_keyword_list(words)) image_pane.update() search.textChanged.connect(on_typed)
def initUI(self): wid = QWidget(self) self.setCentralWidget(wid) hbox = QHBoxLayout() wid.setLayout(hbox) inputAct = QAction(QIcon('exit.png'), 'Input file', self) inputAct.setShortcut('Ctrl+I') inputAct.setStatusTip('Input File') inputAct.triggered.connect(self.openInputImage) targetAct = QAction(QIcon('exit.png'), 'Target file', self) targetAct.setShortcut('Ctrl+T') targetAct.setStatusTip('Target File') targetAct.triggered.connect(self.openTargetImage) mainMenu = self.menuBar() fileMenu = mainMenu.addMenu('File') fileMenu.addAction(inputAct) fileMenu.addAction(targetAct) self.left = QGroupBox() self.left.setTitle("Input") self.mid = QGroupBox() self.mid.setTitle("Target") self.right = QGroupBox() self.right.setTitle("Result") splitter1 = QSplitter(Qt.Horizontal) splitter1.addWidget(self.left) splitter1.addWidget(self.mid) splitter1.addWidget(self.right) splitter1.setSizes([100, 100, 100]) #button self.bottom = QGroupBox() button = QPushButton('Equalize Histogram', self) button.clicked.connect(self.histogramButtonClicked) BUTTON_SIZE = QSize(100, 100) button.setMinimumSize(BUTTON_SIZE) bot_layout = QHBoxLayout() bot_layout.addWidget(button) self.bottom.setLayout(bot_layout) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(splitter1) splitter2.addWidget(self.bottom) splitter2.setSizes([400, 100]) hbox.addWidget(splitter2) QApplication.setStyle(QStyleFactory.create('Cleanlooks')) self.setGeometry(1000, 1000, 1000, 1000) self.setWindowTitle('CV') self.show()
def make_tab(self): self.update_chkbx() '''file dialog section''' self.btn_openfile = QPushButton("Select File") self.btn_openfile.clicked.connect(self.getfile) self.show_filename = QLabel("No file selected") self.btn_openfile.setToolTip( 'click to select the file containing the residual data') '''button section''' # temporarily stop the realtime update self.btn_plot_data = QPushButton('stop') self.btn_plot_data.setToolTip('Click to stop real time data gathering') # setting size of button (width,height) self.btn_plot_data.resize(50, 50) self.btn_plot_data.clicked.connect(self.timer_startstop) # this is a one-column list with the start/stop button at the top # followed by the list of lines self.btn_layout = QVBoxLayout() self.btn_layout.addWidget(self.btn_openfile) self.btn_layout.addWidget(self.show_filename) self.btn_layout.addWidget(self.btn_plot_data) for i in range(len(self.chkbx)): print("i=", i) self.btn_layout.addWidget(self.chkbx[i]) # this adds stretch, so the button is always top-aligned (in a vbox) self.btn_layout.addStretch() '''left-side layout''' left = QFrame() left.setLayout(self.btn_layout) self.figure = MatplotlibFigure() # combine the buttons and the canvas in a splitter layout splitter1 = QSplitter(QtCore.Qt.Horizontal) splitter1.addWidget(left) splitter1.addWidget(self.figure) splitter1.setSizes([75, 700]) '''master layout of tab''' self.tab = QWidget() # create tab with horizontal layout self.tab.layout = QHBoxLayout() # add the last splitter to the layout self.tab.layout.addWidget(splitter1) self.tab.setLayout(self.tab.layout) self.tabs.addTab(self.tab, 'Convergence plot') checklist = [] for c in self.chkbx: checklist.append(c.isChecked()) self.figure.plot(checklist, self.filename)
def on_Search(self): if(self.F_DJBH.text()!=''): self.DataTable.setVisible(False) btncont = self.layout.count() #widget = QtWidgets.QTableView() widget = DataGrid() # self.widget.setGeometry(10, 10, 380, 240) self.layout.addWidget(widget) widget2 = QtWidgets.QTableView() self.layout.addWidget(widget2) topleft = QFrame() topleft.setFrameShape(QFrame.StyledPanel) bottom = QFrame() bottom.setFrameShape(QFrame.StyledPanel) splitter1 = QSplitter() textedit = QTextEdit() splitter1.addWidget(topleft) splitter1.addWidget(textedit) splitter1.setSizes([200, 100]) splitter2 = QSplitter() splitter2.addWidget(splitter1) splitter2.addWidget(bottom) widget2 = QWidget() song = QtWidgets.QLabel('难得') gridlayout = QtWidgets.QGridLayout() gridlayout.addWidget(song, 0, 0) widget2.setLayout(gridlayout) self.layout.addWidget(splitter2) self.layout.addWidget(splitter2) self.layout.addWidget(splitter2) self.layout.addWidget(widget2) self.connectDB() # QW1 = QWidget() # DjinfoW1 = ttt.Czq() # # DjinfoW1.setupUi(QW1) # 将子页面添加到对应控件QW变量 # gridlayout1 = QtWidgets.QGridLayout() # QW1.setLayout(gridlayout1) # self.layout.addWidget(QW1) # qb = QTableInfo.BookStorageViewer() # qb.show() # QMessageBox.information(self, "单据编号", # self.tr("单据编号为空")) else: self.DataTable.setVisible(True) QMessageBox.information(self, "提示", self.tr("单据编号为空"))
def splitter(first, second, direction=Qt.Vertical, size=None): split_widget = QSplitter(direction) split_widget.addWidget(first) split_widget.addWidget(second) if size is not None: split_widget.setSizes(size) return split_widget
def getSplitter(self): splitter = QSplitter(Qt.Horizontal) # Give both boxes a minimum size so the minimumSizeHint will be # ignored when splitter.setSizes is called below for widget in self.editBox, self.previewBox: widget.setMinimumWidth(125) splitter.addWidget(widget) splitter.setSizes((50, 50)) splitter.setChildrenCollapsible(False) return splitter
def getSplitter(self, index): splitter = QSplitter(Qt.Horizontal) # Give both boxes a minimum size so the minimumSizeHint will be # ignored when splitter.setSizes is called below for widget in self.editBoxes[index], self.previewBoxes[index]: widget.setMinimumWidth(125) splitter.addWidget(widget) splitter.setSizes((50, 50)) splitter.setChildrenCollapsible(False) return splitter
def __init__(self, widgets): super(QResizableWidget, self).__init__() layout = QVBoxLayout() splitter = QSplitter(QtCore.Qt.Horizontal) splitter.setStretchFactor(1, 1) for widget in widgets: splitter.addWidget(widget) splitter.setSizes([200, 200]) layout.addWidget(splitter) self.setLayout(layout)
def __init__(self, chat_window, nick, parent=None): QWidget.__init__(self, parent) self.chat_window = chat_window self.nick = nick self.disabled = False self.cleared = False self.url_regex = re.compile(URL_REGEX) self.chat_log = QTextBrowser() self.chat_log.setOpenExternalLinks(True) self.chat_input = QTextEdit() self.chat_input.textChanged.connect(self.chatInputTextChanged) self.send_button = QPushButton("Send") self.send_button.clicked.connect(self.sendMessage) # Set the min height for the chatlog and a matching fixed height for the send button chat_input_font_metrics = QFontMetrics(self.chat_input.font()) self.chat_input.setMinimumHeight(chat_input_font_metrics.lineSpacing() * 3) self.send_button.setFixedHeight(chat_input_font_metrics.lineSpacing() * 3) hbox = QHBoxLayout() hbox.addWidget(self.chat_input) hbox.addWidget(self.send_button) # Put the chatinput and send button in a wrapper widget so they may be added to the splitter chat_input_wrapper = QWidget() chat_input_wrapper.setLayout(hbox) chat_input_wrapper.setMinimumHeight(chat_input_font_metrics.lineSpacing() * 3.7) # Put the chat log and chat input into a splitter so the user can resize them at will splitter = QSplitter(Qt.Vertical) splitter.addWidget(self.chat_log) splitter.addWidget(chat_input_wrapper) splitter.setSizes([int(parent.height()), 1]) hbox = QHBoxLayout() hbox.addWidget(splitter) self.setLayout(hbox) self.typing_timer = QTimer() self.typing_timer.setSingleShot(True) self.typing_timer.timeout.connect(self.stoppedTyping)
def splitViewSpace(self, viewspace, orientation): """Split the given view. If orientation == Qt.Horizontal, adds a new view to the right. If orientation == Qt.Vertical, adds a new view to the bottom. """ active = viewspace is self.activeViewSpace() splitter = viewspace.parentWidget() newspace = ViewSpace(self) if splitter.count() == 1: splitter.setOrientation(orientation) size = splitter.sizes()[0] splitter.addWidget(newspace) splitter.setSizes([size / 2, size / 2]) elif splitter.orientation() == orientation: index = splitter.indexOf(viewspace) splitter.insertWidget(index + 1, newspace) else: index = splitter.indexOf(viewspace) newsplitter = QSplitter() newsplitter.setOrientation(orientation) sizes = splitter.sizes() splitter.insertWidget(index, newsplitter) newsplitter.addWidget(viewspace) splitter.setSizes(sizes) size = newsplitter.sizes()[0] newsplitter.addWidget(newspace) newsplitter.setSizes([size / 2, size / 2]) self._viewSpaces.insert(0, newspace) newspace.showDocument(viewspace.document()) if active: newspace.activeView().setFocus() self.actionCollection.window_close_view.setEnabled(self.canCloseViewSpace()) self.actionCollection.window_close_others.setEnabled(self.canCloseViewSpace())
class DatabaseContainer(QSplitter): def __init__(self, orientation=Qt.Vertical): QSplitter.__init__(self, orientation) self.pfile = None self._hsplitter = QSplitter(Qt.Horizontal) self.lateral_widget = lateral_widget.LateralWidget() self._hsplitter.addWidget(self.lateral_widget) self.table_widget = table_widget.TableWidget() self._hsplitter.addWidget(self.table_widget) self.addWidget(self._hsplitter) self.query_container = query_container.QueryContainer(self) self.addWidget(self.query_container) self.modified = False self.__nquery = 1 # Connections # FIXME self.lateral_widget.itemClicked.connect( lambda: self.table_widget.stacked.setCurrentIndex( self.lateral_widget.row())) # For change table widget item when up/down # see issue #39 self.lateral_widget.itemSelectionChanged.connect( lambda: self.table_widget.stacked.setCurrentIndex( self.lateral_widget.row())) self.query_container.saveEditor['PyQt_PyObject'].connect( self.save_query) self.setSizes([1, 1]) def dbname(self): """ Return display name """ return self.pfile.display_name def is_new(self): return self.pfile.is_new def create_database(self, data): for table in data.get('tables'): # Get data table_name = table.get('name') header = table.get('header') tuples = table.get('tuples') # Create relation rela = relation.Relation() rela.header = header # Table view widget table_view = custom_table.Table() # Model model = QStandardItemModel() model.setHorizontalHeaderLabels(header) # Populate table view row_count = 0 for row in tuples: for col_count, i in enumerate(row): item = QStandardItem(i) # Set read only item.setFlags(item.flags() & ~Qt.ItemIsEditable) model.setItem(row_count, col_count, item) rela.insert(row) row_count += 1 # Set table model table_view.setModel(model) # Add relation to relations dict self.table_widget.add_relation(table_name, rela) # Add table to stacked self.table_widget.stacked.addWidget(table_view) # Add table name to list widget self.lateral_widget.add_item(table_name, rela.count()) # Select first item first_item = self.lateral_widget.topLevelItem(0) first_item.setSelected(True) def load_relation(self, filenames): for filename in filenames: with open(filename) as f: csv_reader = csv.reader(f) header = next(csv_reader) rel = relation.Relation() rel.header = header for i in csv_reader: rel.insert(i) relation_name = file_manager.get_basename(filename) if not self.table_widget.add_relation(relation_name, rel): QMessageBox.information(self, self.tr("Information"), self.tr("There is already a " "relationship with name " "'{}'".format( relation_name))) return False self.table_widget.add_table(rel, relation_name) self.lateral_widget.add_item(relation_name, rel.count()) return True def delete_relation(self): selected_items = self.lateral_widget.selectedItems() if not selected_items: return False current_row = 0 if self.lateral_widget.row() != -1: current_row = self.lateral_widget.row() if len(selected_items) > 1: msg = self.tr("Are you sure you want to delete " "the selected relations?") else: msg = self.tr("Are you sure you want to delete " "the relation <b>{}</b>?".format( self.lateral_widget.item_text(current_row))) msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle(self.tr("Confirmation")) msgbox.setText(msg) msgbox.addButton(self.tr("No"), QMessageBox.NoRole) yes_btn = msgbox.addButton(self.tr("Yes"), QMessageBox.YesRole) palette = QPalette() palette.setColor(QPalette.Button, QColor("#cc575d")) palette.setColor(QPalette.ButtonText, QColor("white")) yes_btn.setPalette(palette) msgbox.exec_() r = msgbox.clickedButton() if r == yes_btn: for item in selected_items: index = self.lateral_widget.indexOfTopLevelItem(item) # Remove from list self.lateral_widget.takeTopLevelItem(index) # Remove table self.table_widget.remove_table(index) # Remove relation self.table_widget.remove_relation(item.name) return True def __on_data_table_changed(self, row, col, data): current_relation = self.lateral_widget.current_text() # Relation to be update rela = self.table_widget.relations.get(current_relation) # Clear old content rela.clear() current_table = self.table_widget.stacked.currentWidget() model = current_table.model() for i in range(model.rowCount()): reg = [] for j in range(model.columnCount()): if row == i and col == j: reg.append(data) else: reg.append(model.item(i, j).text()) # Insert new content rela.insert(reg) # Update relation self.table_widget.relations[current_relation] = rela def new_query(self, filename): editor_tab_at = self.query_container.is_open(filename) if editor_tab_at != -1: self.query_container.set_focus_editor_tab(editor_tab_at) else: query_widget = query_container.QueryWidget() # Create object file ffile = pfile.File(filename) editor = query_widget.get_editor() editor.pfile = ffile if not filename: ffile.filename = 'untitled_{n}.pqf'.format(n=self.__nquery) else: content = ffile.read() editor.setPlainText(content) self.query_container.add_tab(query_widget, ffile.display_name) self.__nquery += 1 def save_query(self, editor): if not editor: editor = self.query_container.currentWidget().get_editor() if editor.is_new: return self.save_query_as(editor) # Get content of editor content = editor.toPlainText() try: editor.pfile.save(content=content) except Exception as reason: QMessageBox.critical(self, "Error", self.tr("The file couldn't be saved!" "\n\n{}".format(reason))) return False editor.saved() return editor.pfile.filename def save_query_as(self, editor=None): filename = QFileDialog.getSaveFileName(self, self.tr("Save File"), editor.name, "Pireal query files(*.pqf)") filename = filename[0] if not filename: return # Get the content content = editor.toPlainText() # Write the file editor.pfile.save(content=content, new_fname=filename) editor.saved() def execute_queries(self): self.query_container.execute_queries() def execute_selection(self): editor = self.query_container.currentWidget().get_editor() text_cursor = editor.textCursor() if text_cursor.hasSelection(): query = text_cursor.selectedText() self.query_container.execute_queries(query) def showEvent(self, event): QSplitter.showEvent(self, event) qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) hsizes = qsettings.value('hsplitter_sizes', None) if hsizes is not None: self._hsplitter.restoreState(hsizes) else: self._hsplitter.setSizes([1, self._hsplitter.width() / 3]) vsizes = qsettings.value('vsplitter_sizes', None) if vsizes is not None: self.restoreState(vsizes) else: self.setSizes([self.height() / 3, self.height() / 3]) def save_sizes(self): """ Save sizes of Splitters """ qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) qsettings.setValue('hsplitter_sizes', self._hsplitter.saveState()) qsettings.setValue('vsplitter_sizes', self.saveState())
def _createUI(self): # Create components fontList = QFontComboBox(self) fontSize = QSpinBox(self) chars = ClickableLabel(self) chars.topWidget = self chars.setMouseTracking(True) chars.setCursor(Qt.PointingHandCursor) charScroller = QScrollArea(self) charScroller.setWidget(chars) charPreview = QLabel(self) charPreviewScroller = QScrollArea(self) charPreviewScroller.setWidget(charPreview) btnSave = QPushButton('Save...', self) bottomLabel = QLabel('', self) charFrom = QSpinBox(self) charTo = QSpinBox(self) # Components layout mainBox = QVBoxLayout(self) topBox = QHBoxLayout(self) topBox.addWidget(QLabel('Font list:', self)) topBox.addWidget(fontList, 1) topBox.addWidget(QLabel(' Font size:', self)) topBox.addWidget(fontSize) mainBox.addLayout(topBox) rangeBox = QHBoxLayout(self) rangeBox.addWidget(QLabel('Char list for pack.'), 1) rangeBox.addWidget(QLabel('Start with')) rangeBox.addWidget(charFrom) rangeBox.addWidget(QLabel('to')) rangeBox.addWidget(charTo) mainBox.addLayout(rangeBox) splBox = QSplitter(Qt.Vertical, self) splBox.addWidget(charScroller) splBox.addWidget(charPreviewScroller) mainBox.addWidget(splBox) bottBox = QHBoxLayout(self) bottBox.addWidget(btnSave, 0, Qt.AlignLeft) bottBox.addWidget(bottomLabel) mainBox.addLayout(bottBox) # Configure and assign handlers fontList.activated[str].connect(lambda: self.buildCharList()) fontSize.setValue(11) fontSize.valueChanged[str].connect(lambda: self.buildCharList()) fontSize.setRange(5, 99) charFrom.setRange(0, 255) charFrom.setValue(0) charFrom.valueChanged[str].connect(lambda: self.buildCharList()) charTo.setRange(0, 255) charTo.setValue(255) charTo.valueChanged[str].connect(lambda: self.buildCharList()) chars.setPixmap(QPixmap()) btnSave.clicked.connect(self.save) splBox.setSizes([100, 300]) # Registering to access the components inside the class self.fontList = fontList self.fontSize = fontSize self.charScroller = charScroller self.charPreviewScroller = charPreviewScroller self.chars = chars self.charPreview = charPreview self.bottomLabel = bottomLabel self.charFrom = charFrom self.charTo = charTo self.splBox = splBox
class OTMainWindow(QWidget): def __init__(self, parent=None): super(OTMainWindow, self).__init__(parent, Qt.Window) self.setWindowTitle('OPC Python Tester') self.layout = QVBoxLayout() # self.tree = QTreeWidget(self) self.tree.setHeaderLabel('OPC server tree') self.tree_root = QTreeWidgetItem() self.tree_root.setText(0, 'not connected') self.tree.addTopLevelItem(self.tree_root) self.tree.itemDoubleClicked.connect(self.on_tree_item_double_clicked) # self.table = QTableWidget(self) self.table.setRowCount(0) self.table_column_labels = [ 'item_id', 'value', 'type', 'access', 'quality', 'timestamp'] self.table.setColumnCount(len(self.table_column_labels)) self.table.setHorizontalHeaderLabels(self.table_column_labels) self.table.horizontalHeader().setStretchLastSection(True) # self.splitter = QSplitter(Qt.Horizontal, self) self.splitter.setChildrenCollapsible(False) self.splitter.setHandleWidth(10) self.layout.addWidget(self.splitter) # final self.splitter.addWidget(self.tree) self.splitter.addWidget(self.table) self.splitter.setSizes([150, 300]) self.setLayout(self.layout) # self.opcsrv = None self.cur_server_info = {} self.cur_comp_name = '' self.watched_itemids = [] self.ssdialog = ServerSelectDialog(self) ssel_ret = self.ssdialog.exec_() if ssel_ret == QDialog.Accepted: self.do_connect(self.ssdialog.selected_server, self.ssdialog.selected_comp_name) else: print('Connection cancelled') self.timer = QTimer(self) self.timer.timeout.connect(self.on_timer_timeout) self.timer.start(1000) # every 1 second def do_connect(self, srv_info: dict, comp_name: str): print('Connecting to "{0}" ({1}) on comp: {2}...'.format( srv_info['desc'], srv_info['guid'], comp_name)) self.opcsrv = opc_helper.opc_connect(srv_info['guid'], comp_name) if self.opcsrv is None: return self.cur_comp_name = comp_name self.cur_server_info = srv_info print(self.opcsrv.get_status()) self.fill_tree() def fill_tree(self): self.tree.clear() if self.opcsrv is None: return self.tree_root = QTreeWidgetItem(self.tree) self.tree_root.setChildIndicatorPolicy(QTreeWidgetItem.DontShowIndicatorWhenChildless) root_title = '{0}'.format(self.cur_server_info['desc']) if self.cur_comp_name != '': root_title = '{0} ({1})'.format(self.cur_server_info['desc'], self.cur_comp_name) self.tree_root.setText(0, root_title) self.tree.addTopLevelItem(self.tree_root) server_tree = self.opcsrv.browse(flat=False) # for oitem in server_tree: self.fill_item(oitem, self.tree_root) def fill_item(self, item: dict, parent: QTreeWidgetItem): tree_item = QTreeWidgetItem() tree_item.setChildIndicatorPolicy(QTreeWidgetItem.DontShowIndicatorWhenChildless) tree_item.setText(0, item['name']) if item['children'] is None: # set userdata = item_id only if this IS a LEAF node tree_item.setData(0, Qt.UserRole, item['item_id']) # column, role, data parent.addChild(tree_item) # recurse into children if item['children'] is not None: for oitem in item['children']: self.fill_item(oitem, tree_item) @pyqtSlot(QTreeWidgetItem, int) def on_tree_item_double_clicked(self, item: QTreeWidgetItem, column: int): # void itemDoubleClicked(QTreeWidgetItem * item, int column) # virtual QVariant data(int column, int role) const item_data = item.data(0, Qt.UserRole) if item_data is None: return item_id = str(item_data) print('Double click on [{0}]'.format(item_id)) self.opcsrv.get_item(item_id) if item_id not in self.watched_itemids: self.watched_itemids.append(item_id) @pyqtSlot() def on_timer_timeout(self): num_items = len(self.watched_itemids) self.table.setRowCount(num_items) i = 0 while i < num_items: item_id = self.watched_itemids[i] item_value = self.opcsrv.get_item(item_id) item_info = self.opcsrv.get_item_info(item_id) # twi = QTableWidgetItem(str(item_id)) self.table.setItem(i, 0, twi) # twi = QTableWidgetItem(str(item_value)) self.table.setItem(i, 1, twi) # twi = QTableWidgetItem(str(item_info['type'])) self.table.setItem(i, 2, twi) # twi = QTableWidgetItem(str(item_info['access_rights'])) self.table.setItem(i, 3, twi) # twi = QTableWidgetItem(str(item_info['quality'])) self.table.setItem(i, 4, twi) # ts_str = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(item_info['timestamp'])) twi = QTableWidgetItem(str(ts_str)) self.table.setItem(i, 5, twi) # i += 1
class _s_CentralWidget(QWidget): ############################################################################### # CentralWidget SIGNALS ############################################################################### """ splitterCentralRotated() """ splitterCentralRotated = pyqtSignal() ############################################################################### def __init__(self, parent=None): super(_s_CentralWidget, self).__init__(parent) self.parent = parent #This variables are used to save the splitter sizes before hide self._splitterMainSizes = None self._splitterAreaSizes = None self.lateralPanel = None hbox = QHBoxLayout(self) hbox.setContentsMargins(0, 0, 0, 0) hbox.setSpacing(0) #Create Splitters to divide the UI in: MainPanel, Explorer, Misc self._splitterArea = QSplitter(Qt.Horizontal) self._splitterMain = QSplitter(Qt.Vertical) #Create scrollbar for follow mode self.scrollBar = QScrollBar(Qt.Vertical, self) self.scrollBar.setFixedWidth(20) self.scrollBar.setToolTip('Follow Mode: Scroll the Editors together') self.scrollBar.hide() self.scrollBar.valueChanged[int].connect(self.move_follow_scrolls) #Add to Main Layout hbox.addWidget(self.scrollBar) hbox.addWidget(self._splitterArea) def insert_central_container(self, container): self.mainContainer = container self._splitterMain.insertWidget(0, container) def insert_lateral_container(self, container): self.lateralPanel = LateralPanel(container) self._splitterArea.insertWidget(0, self.lateralPanel) def insert_bottom_container(self, container): self.misc = container self._splitterMain.insertWidget(1, container) def showEvent(self, event): #Show Event QWidget.showEvent(self, event) #Avoid recalculate the panel sizes if they are already loaded if self._splitterArea.count() == 2: return #Rearrange widgets on Window self._splitterArea.insertWidget(0, self._splitterMain) if not event.spontaneous(): self.change_misc_visibility() if bin(settings.UI_LAYOUT)[-1] == '1': self.splitter_central_rotate() if bin(settings.UI_LAYOUT >> 1)[-1] == '1': self.splitter_misc_rotate() if bin(settings.UI_LAYOUT >> 2)[-1] == '1': self.splitter_central_orientation() qsettings = QSettings(resources.SETTINGS_PATH, QSettings.IniFormat) #Lists of sizes as list of QVariant- heightList = [QVariant, QVariant] heightList = list(qsettings.value("window/central/mainSize", [(self.height() / 3) * 2, self.height() / 3])) widthList = list(qsettings.value("window/central/areaSize", [(self.width() / 6) * 5, self.width() / 6])) self._splitterMainSizes = [int(heightList[0]), int(heightList[1])] self._splitterAreaSizes = [int(widthList[0]), int(widthList[1])] #Set the sizes to splitters #self._splitterMain.setSizes(self._splitterMainSizes) self._splitterMain.setSizes(self._splitterMainSizes) self._splitterArea.setSizes(self._splitterAreaSizes) self.misc.setVisible( qsettings.value("window/show_misc", False, type=bool)) def change_misc_visibility(self, on_start=False): if self.misc.isVisible(): self._splitterMainSizes = self._splitterMain.sizes() self.misc.hide() widget = self.mainContainer.get_actual_widget() if widget: widget.setFocus() else: self.misc.show() self.misc.gain_focus() def change_main_visibility(self): if self.mainContainer.isVisible(): self.mainContainer.hide() else: self.mainContainer.show() def change_explorer_visibility(self, force_hide=False): if self.lateralPanel.isVisible() or force_hide: self._splitterAreaSizes = self._splitterArea.sizes() self.lateralPanel.hide() else: self.lateralPanel.show() def splitter_central_rotate(self): w1, w2 = self._splitterArea.widget(0), self._splitterArea.widget(1) self._splitterArea.insertWidget(0, w2) self._splitterArea.insertWidget(1, w1) self.splitterCentralRotated.emit() def splitter_central_orientation(self): if self._splitterArea.orientation() == Qt.Horizontal: self._splitterArea.setOrientation(Qt.Vertical) else: self._splitterArea.setOrientation(Qt.Horizontal) def splitter_misc_rotate(self): w1, w2 = self._splitterMain.widget(0), self._splitterMain.widget(1) self._splitterMain.insertWidget(0, w2) self._splitterMain.insertWidget(1, w1) def splitter_misc_orientation(self): if self._splitterMain.orientation() == Qt.Horizontal: self._splitterMain.setOrientation(Qt.Vertical) else: self._splitterMain.setOrientation(Qt.Horizontal) def get_area_sizes(self): if self.lateralPanel.isVisible(): self._splitterAreaSizes = self._splitterArea.sizes() return self._splitterAreaSizes def get_main_sizes(self): if self.misc.isVisible(): self._splitterMainSizes = self._splitterMain.sizes() return self._splitterMainSizes def enable_follow_mode_scrollbar(self, val): if val: editorWidget = self.mainContainer.get_actual_editor() maxScroll = editorWidget.verticalScrollBar().maximum() position = editorWidget.verticalScrollBar().value() self.scrollBar.setMaximum(maxScroll) self.scrollBar.setValue(position) self.scrollBar.setVisible(val) def move_follow_scrolls(self, val): widget = self.mainContainer._tabMain.currentWidget() diff = widget._sidebarWidget.highest_line - val s1 = self.mainContainer._tabMain.currentWidget().verticalScrollBar() s2 = self.mainContainer._tabSecondary.\ currentWidget().verticalScrollBar() s1.setValue(val) s2.setValue(val + diff)
class QuadView(QWidget): def __init__(self, parent, view1, view2, view3, view4=None): QWidget.__init__(self, parent) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.installEventFilter(self) self.dockableContainer = [] self.layout = QVBoxLayout() self.setLayout(self.layout) self.layout.setContentsMargins(0, 0, 0, 0) self.layout.setSpacing(0) self.splitVertical = QSplitter(Qt.Vertical, self) self.layout.addWidget(self.splitVertical) self.splitHorizontal1 = QSplitter(Qt.Horizontal, self.splitVertical) self.splitHorizontal1.setObjectName("splitter1") self.splitHorizontal2 = QSplitter(Qt.Horizontal, self.splitVertical) self.splitHorizontal2.setObjectName("splitter2") self.splitHorizontal1.splitterMoved.connect(self.horizontalSplitterMoved) self.splitHorizontal2.splitterMoved.connect(self.horizontalSplitterMoved) self.imageView2D_1 = view1 self.imageView2D_2 = view2 self.imageView2D_3 = view3 self.dock1_ofSplitHorizontal1 = ImageView2DDockWidget(self.imageView2D_1) self.dock1_ofSplitHorizontal1.connectHud() self.dockableContainer.append(self.dock1_ofSplitHorizontal1) self.dock1_ofSplitHorizontal1.onDockButtonClicked.connect( lambda arg=self.dock1_ofSplitHorizontal1: self.on_dock(arg) ) self.dock1_ofSplitHorizontal1.onMaxButtonClicked.connect( lambda arg=self.dock1_ofSplitHorizontal1: self.on_max(arg) ) self.dock1_ofSplitHorizontal1.onMinButtonClicked.connect( lambda arg=self.dock1_ofSplitHorizontal1: self.on_min(arg) ) self.splitHorizontal1.addWidget(self.dock1_ofSplitHorizontal1) self.dock2_ofSplitHorizontal1 = ImageView2DDockWidget(self.imageView2D_2) self.dock2_ofSplitHorizontal1.onDockButtonClicked.connect( lambda arg=self.dock2_ofSplitHorizontal1: self.on_dock(arg) ) self.dock2_ofSplitHorizontal1.onMaxButtonClicked.connect( lambda arg=self.dock2_ofSplitHorizontal1: self.on_max(arg) ) self.dock2_ofSplitHorizontal1.onMinButtonClicked.connect( lambda arg=self.dock2_ofSplitHorizontal1: self.on_min(arg) ) self.dock2_ofSplitHorizontal1.connectHud() self.dockableContainer.append(self.dock2_ofSplitHorizontal1) self.splitHorizontal1.addWidget(self.dock2_ofSplitHorizontal1) self.dock1_ofSplitHorizontal2 = ImageView2DDockWidget(self.imageView2D_3) self.dock1_ofSplitHorizontal2.onDockButtonClicked.connect( lambda arg=self.dock1_ofSplitHorizontal2: self.on_dock(arg) ) self.dock1_ofSplitHorizontal2.onMaxButtonClicked.connect( lambda arg=self.dock1_ofSplitHorizontal2: self.on_max(arg) ) self.dock1_ofSplitHorizontal2.onMinButtonClicked.connect( lambda arg=self.dock1_ofSplitHorizontal2: self.on_min(arg) ) self.dock1_ofSplitHorizontal2.connectHud() self.dockableContainer.append(self.dock1_ofSplitHorizontal2) self.splitHorizontal2.addWidget(self.dock1_ofSplitHorizontal2) self.dock2_ofSplitHorizontal2 = ImageView2DDockWidget(view4) self.dockableContainer.append(self.dock2_ofSplitHorizontal2) self.splitHorizontal2.addWidget(self.dock2_ofSplitHorizontal2) # this is a hack: with 0 ms it does not work... QTimer.singleShot(250, self._resizeEqual) def _resizeEqual(self): if not all([dock.isVisible() for dock in self.dockableContainer]): return w, h = ( self.size().width() - self.splitHorizontal1.handleWidth(), self.size().height() - self.splitVertical.handleWidth(), ) self.splitVertical.setSizes([h // 2, h // 2]) if self.splitHorizontal1.count() == 2 and self.splitHorizontal2.count() == 2: # docks = [self.imageView2D_1, self.imageView2D_2, self.imageView2D_3, self.testView4] docks = [] for splitter in [self.splitHorizontal1, self.splitHorizontal2]: for i in range(splitter.count()): docks.append(splitter.widget(i).graphicsView) w1 = [docks[i].minimumSize().width() for i in [0, 2]] w2 = [docks[i].minimumSize().width() for i in [1, 3]] wLeft = max(w1) wRight = max(w2) if wLeft > wRight and wLeft > w // 2: wRight = w - wLeft elif wRight >= wLeft and wRight > w // 2: wLeft = w - wRight else: wLeft = w // 2 wRight = w // 2 self.splitHorizontal1.setSizes([wLeft, wRight]) self.splitHorizontal2.setSizes([wLeft, wRight]) def eventFilter(self, obj, event): if event.type() in [QEvent.WindowActivate, QEvent.Show]: self._synchronizeSplitter() return False def _synchronizeSplitter(self): sizes1 = self.splitHorizontal1.sizes() sizes2 = self.splitHorizontal2.sizes() if len(sizes1) > 0 and sizes1[0] > 0: self.splitHorizontal2.setSizes(sizes1) elif len(sizes2) > 0 and sizes2[0] > 0: self.splitHorizontal1.setSizes(sizes2) def resizeEvent(self, event): QWidget.resizeEvent(self, event) self._synchronizeSplitter() def horizontalSplitterMoved(self, x, y): if self.splitHorizontal1.count() != 2 or self.splitHorizontal2.count() != 2: return sizes = self.splitHorizontal1.sizes() # What. Nr2 if self.splitHorizontal2.closestLegalPosition(x, y) < self.splitHorizontal2.closestLegalPosition(x, y): sizeLeft = self.splitHorizontal1.closestLegalPosition(x, y) else: sizeLeft = self.splitHorizontal2.closestLegalPosition(x, y) sizeRight = sizes[0] + sizes[1] - sizeLeft sizes = [sizeLeft, sizeRight] self.splitHorizontal1.setSizes(sizes) self.splitHorizontal2.setSizes(sizes) def addStatusBar(self, bar): self.statusBar = bar self.layout.addLayout(self.statusBar) def setGrayScaleToQuadStatusBar(self, gray): self.quadViewStatusBar.setGrayScale(gray) def setMouseCoordsToQuadStatusBar(self, x, y, z): self.quadViewStatusBar.setMouseCoords(x, y, z) def ensureMaximized(self, axis): """ Maximize the view for the given axis if it isn't already maximized. """ axisDict = { 0: self.dock2_ofSplitHorizontal1, # x 1: self.dock1_ofSplitHorizontal2, # y 2: self.dock1_ofSplitHorizontal1, } # z if not axisDict[axis]._isMaximized: self.switchMinMax(axis) def ensureMinimized(self, axis): """ Minimize the view for the given axis if it isn't already minimized. """ axisDict = { 0: self.dock2_ofSplitHorizontal1, # x 1: self.dock1_ofSplitHorizontal2, # y 2: self.dock1_ofSplitHorizontal1, } # z if axisDict[axis]._isMaximized: self.switchMinMax(axis) def switchMinMax(self, axis): """Switch an AxisViewWidget between from minimized to maximized and vice versa. Keyword arguments: axis -- the axis which is represented by the widget (no default) either string or integer 'x' - 0 'y' - 1 'z' - 2 """ # TODO: get the mapping information from where it is set! if this is not # done properly - do it properly if type(axis) == str: axisDict = { "x": self.dock2_ofSplitHorizontal1, # x "y": self.dock1_ofSplitHorizontal2, # y "z": self.dock1_ofSplitHorizontal1, } # z elif type(axis) == int: axisDict = { 0: self.dock2_ofSplitHorizontal1, # x 1: self.dock1_ofSplitHorizontal2, # y 2: self.dock1_ofSplitHorizontal1, } # z dockWidget = axisDict.pop(axis) for dWidget in list(axisDict.values()): if dWidget._isMaximized: dWidget.graphicsView._hud.maximizeButtonClicked.emit() dockWidget.graphicsView._hud.maximizeButtonClicked.emit() def switchXMinMax(self): self.switchMinMax("x") def switchYMinMax(self): self.switchMinMax("y") def switchZMinMax(self): self.switchMinMax("z") def on_dock(self, dockWidget): if dockWidget._isDocked: dockWidget.undockView() self.on_min(dockWidget) dockWidget.minimizeView() else: dockWidget.dockView() def on_max(self, dockWidget): dockWidget.setVisible(True) for dock in self.dockableContainer: if not dockWidget == dock: dock.setVisible(False) # Force sizes to be updated now QApplication.processEvents() # On linux, the vertical splitter doesn't seem to refresh unless we do so manually # Presumably, this is a QT bug. self.splitVertical.refresh() # Viewport doesn't update automatically... view = dockWidget.graphicsView view.viewport().setGeometry(view.rect()) def on_min(self, dockWidget): for dock in self.dockableContainer: dock.setVisible(True) # Force sizes to be updated now QApplication.processEvents() self._resizeEqual() # Viewports don't update automatically... for dock in self.dockableContainer: view = dock.graphicsView if hasattr(view, "viewport"): view.viewport().setGeometry(view.rect())
class ScriptingWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.editor = PythonEditor(self) self.fileChooser = FileChooser(self) self.fileChooser.fileOpened.connect(self.openFile) self.outputEdit = OutputEdit(self) splitter = QSplitter(self) self.vSplitter = QSplitter(Qt.Vertical, splitter) self.vSplitter.addWidget(self.editor) self.vSplitter.addWidget(self.outputEdit) self.vSplitter.setStretchFactor(0, 1) self.vSplitter.setStretchFactor(1, 0) splitter.addWidget(self.fileChooser) splitter.addWidget(self.vSplitter) splitter.setStretchFactor(0, 0) splitter.setStretchFactor(1, 1) statusBar = ScriptingStatusBar(self) self.setCentralWidget(splitter) self.setStatusBar(statusBar) self.newFile() self.editor.modificationChanged.connect(self.setWindowModified) statusBar.setPosition(self.editor.textCursor()) self.editor.cursorPositionChanged.connect( lambda: statusBar.setPosition(self.sender().textCursor())) statusBar.setIndent(self.editor.indent()) self.editor.indentChanged.connect(statusBar.setIndent) statusBar.indentModified.connect(self.editor.setIndent) statusBar.positionClicked.connect(self.gotoLine) statusBar.clearButtonClicked.connect(self.outputEdit.clear) statusBar.runButtonClicked.connect(self.runScript) gotoLineShortcut = QShortcut(QKeySequence("Ctrl+G"), self) gotoLineShortcut.activated.connect(self.gotoLine) self.readSettings() splitter.splitterMoved.connect(self.writeSettings) self.vSplitter.splitterMoved.connect(self.writeSettings) def readSettings(self): geometry = settings.scriptingWindowGeometry() if geometry: self.restoreGeometry(geometry) sizes = settings.scriptingWindowHSplitterSizes() if sizes: splitter = self.centralWidget() splitter.setSizes(sizes) sizes = settings.scriptingWindowVSplitterSizes() if sizes: self.vSplitter.setSizes(sizes) def writeSettings(self): settings.setScriptingWindowGeometry(self.saveGeometry()) # splitters don't report a correct size until the window is visible if not self.isVisible(): return splitter = self.centralWidget() settings.setScriptingWindowHSplitterSizes(splitter.sizes()) settings.setScriptingWindowVSplitterSizes(self.vSplitter.sizes()) def setupMenu(self, menuBar): fileMenu = menuBar.fetchMenu(Entries.File) fileMenu.fetchAction(Entries.File_New, self.newFile) fileMenu.fetchAction(Entries.File_Open, self.openFile) fileMenu.fetchAction(Entries.File_Save, self.saveFile) fileMenu.fetchAction(Entries.File_Save_As, self.saveFileAs) fileMenu.addSeparator() fileMenu.fetchAction(Entries.File_Close, self.close) @property def currentPath(self): return self._currentPath @currentPath.setter def currentPath(self, currentPath): self._currentPath = currentPath if self._currentPath is None: title = self.tr("Untitled") else: title = os.path.basename(self._currentPath) self.setWindowTitle(title) def newFile(self): if not self._maybeSaveBeforeExit(): return self.editor.setPlainText(None) self.currentPath = None def openFile(self, path=None): if not self._maybeSaveBeforeExit(): return if path is None: path = self._ioDialog(QFileDialog.AcceptOpen) if path is None: return self.fileChooser.setCurrentFolder(os.path.dirname(path)) with tokenize.open(path) as inputFile: self.editor.setPlainText(inputFile.read()) self.currentPath = path def saveFile(self): if self.currentPath is None: self.saveFileAs() else: self.editor.write(self.currentPath) def saveFileAs(self): path = self._ioDialog(QFileDialog.AcceptSave) if path is not None: self.currentPath = path self.saveFile() # TODO: why not use simple dialogs? def _ioDialog(self, mode): state = settings.scriptingFileDialogState() if mode == QFileDialog.AcceptOpen: title = self.tr("Open File") else: title = self.tr("Save File") dialog = QFileDialog( self, title, None, self.tr("Python file (*.py)")) if state: dialog.restoreState(state) dialog.setAcceptMode(mode) dialog.setDirectory(self.fileChooser.currentFolder()) dialog.setFileMode(QFileDialog.ExistingFile) ok = dialog.exec_() settings.setScriptingWindowFileDialogState(state) if ok: return dialog.selectedFiles()[0] return None def gotoLine(self): newLine, newColumn, ret = GotoLineDialog.getLineColumnNumber(self) if ret and newLine: self.editor.scrollToLine(newLine, newColumn) def runScript(self): app = QApplication.instance() global_vars = app.globals() script = self.editor.toPlainText() streams = [] for channel in ("stdout", "stderr"): stream = OutputStream(channel, self) stream.forward = True stream.messagePassed.connect(self.outputEdit.write) streams.append(stream) try: code = compile(script, "<string>", "exec") exec(code, global_vars) except: traceback.print_exc() for stream in streams: stream.unregisterStream() stream.messagePassed.disconnect(self.outputEdit.write) # ---------- # Qt methods # ---------- def setWindowTitle(self, title): if platformSpecific.appNameInTitle(): title += " – TruFont" super().setWindowTitle("[*]{}".format(title)) def sizeHint(self): return QSize(650, 700) def moveEvent(self, event): self.writeSettings() resizeEvent = moveEvent def closeEvent(self, event): ok = self._maybeSaveBeforeExit() if ok: event.accept() else: event.ignore() def _maybeSaveBeforeExit(self): if self.isWindowModified(): currentFile = self.windowTitle()[3:] ret = CloseMessageBox.getCloseDocument(self, currentFile) if ret == QMessageBox.Save: self.saveFile() return True elif ret == QMessageBox.Discard: return True return False return True
class PanelContainer(QWidget): def __init__(self, panelWin): super(QWidget, self).__init__() self.panelWindow = panelWin self.panelCount = 0 self.mainLayout = QGridLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.splitter = QSplitter(self) self.containerParent = 0 self.mainLayout.addWidget(self.splitter, 0, 0) def splitter(self): return self.splitter def addPanel(self, panel=None): if panel: panel.setParent(self) panel.setContainer(self) self.splitter.addWidget(panel) self.panelCount += 1 self.updatePanelSignals(panel) else: panel = self.createPanel() self.splitter.addWidget(panel) return panel def addPanelSplit(self, panel, direction): panel = PanelWidget(self) if 0 else panel # Store original size origSize = panel.size() # reparent the panel panel.setParent(self) panel.setContainer(self) # set orientation and add the panel self.splitter.setOrientation(direction) self.splitter.addWidget(panel) # add another panel for split panel = self.createPanel() self.splitter.addWidget(panel) sizes = list() origSize *= 0.5 if direction == Qt.Horizontal: sizes.append(origSize.width()) sizes.append(origSize.width()) else: sizes.append(origSize.height()) sizes.append(origSize.height()) self.splitter.setSizes(sizes) self.panelCount += 1 def addContainer(self, child): child = PanelContainer(self) if 0 else child self.splitter.addWidget(child) child.setParentContainer(self) def insertContainer(self, child, index): child = PanelContainer(self) if 0 else child self.splitter.insertWidget(index, child) child.setParentContainer(self) def setParentContainer(self, parent): self.containerParent = parent def parentContainer(self): return self.containerParent def childContainers(self): # childContainers = list() # for index in range(0, self.splitter.count()): # container = self.splitter.widget(index) # if container: # childContainers.append(container) return self.sortedChildren() def panels(self): # panels = list() # for index in range(0, self.splitter.count()): # panel = self.splitter.widget(index) # if panel: # panels.append(panel) return self.sortedChildren() def sortedChildren(self): return (self.splitter.widget(index) for index in range(self.splitter.count())) def numberOfPanels(self): return self.panelCount def createPanel(self): panel = PanelWidget(self) panel.createMenu(WorkbenchWidget.panelNames()) self.connectPanelSignals(panel) self.panelCount += 1 return panel def connectPanelSignals(self, panel): panel = PanelWidget(self) if 0 else panel panel.panelSplit.connect(lambda: self.panelWindow.splitPanel()) panel.panelFloat.connect(lambda : self.panelWindow.floatPanel()) panel.panelClosed.connect(lambda : self.panelWindow.closePanel()) panel.panelMenuTriggered.connect(lambda : self.panelWindow.closePanel()) panel.tabClosed.connect(lambda : self.panelWindow.closePanel()) def updatePanelSignals(self, panel): panel = PanelWidget(self) if 0 else panel panel.panelSplit.disconnect() panel.panelFloat.disconnect() panel.panelClosed.disconnect() panel.panelMenuTriggered.disconnect() panel.tabClosed.disconnect()
def __init__(self, parentWidget, settings): QWidget.__init__(self, parentWidget) self.settings = settings self.theLayout = QHBoxLayout() self.splitter = QSplitter(self) self.theLayout.addWidget(self.splitter) self.browserWidget = BrowserWidget(self, self.settings) self.browserWidget.itemSelected.connect(self.itemSelected) self.tabWidget = QTabWidget(self) tab = QWidget() tabLayout = QVBoxLayout(tab) tab.setLayout(tabLayout) self.editorWidget = EditorWidget(tab) self.editorWidget.setObjectName("EditorWidget1") self.editorWidget.message.connect(self.showMessage) self.editorWidget.titleChanged.connect(self.updateWindowTitle) self.editorWidget.navigate.connect(self.navigate) tabLayout.addWidget(self.editorWidget) self.editTabIdx = self.tabWidget.addTab(tab, "Edit") ############################# self.browser = QWebView(self.tabWidget) self.browser.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.browser.linkClicked.connect(self.navigateWeb) self.webTabIdx = self.tabWidget.addTab(self.browser, "View web") self.pdfTabIdx = self.tabWidget.addTab(QWidget(self.tabWidget), "View pdf") self.textView = QTextEdit(self.tabWidget) self.textView.setReadOnly(True) self.textView.setFontFamily('Courier') self.textView.setFontPointSize(8) self.structureTabIdx = self.tabWidget.addTab(self.textView, "View document structure") self.customView = QTextEdit(self.tabWidget) self.customView.setReadOnly(True) self.customView.setFontFamily('Courier') self.customView.setFontPointSize(10) self.xmlTabIdx = self.tabWidget.addTab(self.customView, "View XML") self.htmlView = QTextEdit(self.tabWidget) self.htmlView.setReadOnly(True) self.htmlView.setFontFamily('Courier') self.htmlView.setFontPointSize(10) self.htmlTabIdx = self.tabWidget.addTab(self.htmlView, "View Html") self.tabWidget.currentChanged.connect(self.tabSelected) # Search/Links widget in lower left corner #################################### self.searchWidget = SearchWidget(self) self.searchWidget.resultSelected.connect(self.navigateDirect) self.toLinksWidget = LinklistWidget(self) self.toLinksWidget.resultSelected.connect(self.navigateDirect) self.fromLinksWidget = LinklistWidget(self) self.fromLinksWidget.resultSelected.connect(self.navigateDirect) self.listsWidget = QTabWidget(self) self.listsWidget.addTab(self.searchWidget, 'Search') self.listsWidget.addTab(self.toLinksWidget, 'Links to') self.listsWidget.addTab(self.fromLinksWidget, 'Links from') ############################################################################### leftWidget = QSplitter(Qt.Vertical, self) leftWidget.addWidget(self.browserWidget) leftWidget.addWidget(self.listsWidget) self.splitter.addWidget(leftWidget) self.splitter.addWidget(self.tabWidget) leftWidget.setSizes([400, 100]) # TODO self.setLayout(self.theLayout) self.splitter.setSizes([100, 400]) # TODO # self.splitter.setChildrenCollapsible(False) self.editorWidget.setEnabled(False)
class CentralWidget(QWidget): l = logging.getLogger('CentralWidget') updateWindowTitle = pyqtSignal(str) def __init__(self, parentWidget, settings): QWidget.__init__(self, parentWidget) self.settings = settings self.theLayout = QHBoxLayout() self.splitter = QSplitter(self) self.theLayout.addWidget(self.splitter) self.browserWidget = BrowserWidget(self, self.settings) self.browserWidget.itemSelected.connect(self.itemSelected) self.tabWidget = QTabWidget(self) tab = QWidget() tabLayout = QVBoxLayout(tab) tab.setLayout(tabLayout) self.editorWidget = EditorWidget(tab) self.editorWidget.setObjectName("EditorWidget1") self.editorWidget.message.connect(self.showMessage) self.editorWidget.titleChanged.connect(self.updateWindowTitle) self.editorWidget.navigate.connect(self.navigate) tabLayout.addWidget(self.editorWidget) self.editTabIdx = self.tabWidget.addTab(tab, "Edit") ############################# self.browser = QWebView(self.tabWidget) self.browser.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.browser.linkClicked.connect(self.navigateWeb) self.webTabIdx = self.tabWidget.addTab(self.browser, "View web") self.pdfTabIdx = self.tabWidget.addTab(QWidget(self.tabWidget), "View pdf") self.textView = QTextEdit(self.tabWidget) self.textView.setReadOnly(True) self.textView.setFontFamily('Courier') self.textView.setFontPointSize(8) self.structureTabIdx = self.tabWidget.addTab(self.textView, "View document structure") self.customView = QTextEdit(self.tabWidget) self.customView.setReadOnly(True) self.customView.setFontFamily('Courier') self.customView.setFontPointSize(10) self.xmlTabIdx = self.tabWidget.addTab(self.customView, "View XML") self.htmlView = QTextEdit(self.tabWidget) self.htmlView.setReadOnly(True) self.htmlView.setFontFamily('Courier') self.htmlView.setFontPointSize(10) self.htmlTabIdx = self.tabWidget.addTab(self.htmlView, "View Html") self.tabWidget.currentChanged.connect(self.tabSelected) # Search/Links widget in lower left corner #################################### self.searchWidget = SearchWidget(self) self.searchWidget.resultSelected.connect(self.navigateDirect) self.toLinksWidget = LinklistWidget(self) self.toLinksWidget.resultSelected.connect(self.navigateDirect) self.fromLinksWidget = LinklistWidget(self) self.fromLinksWidget.resultSelected.connect(self.navigateDirect) self.listsWidget = QTabWidget(self) self.listsWidget.addTab(self.searchWidget, 'Search') self.listsWidget.addTab(self.toLinksWidget, 'Links to') self.listsWidget.addTab(self.fromLinksWidget, 'Links from') ############################################################################### leftWidget = QSplitter(Qt.Vertical, self) leftWidget.addWidget(self.browserWidget) leftWidget.addWidget(self.listsWidget) self.splitter.addWidget(leftWidget) self.splitter.addWidget(self.tabWidget) leftWidget.setSizes([400, 100]) # TODO self.setLayout(self.theLayout) self.splitter.setSizes([100, 400]) # TODO # self.splitter.setChildrenCollapsible(False) self.editorWidget.setEnabled(False) def navigateWeb(self, url): if url.scheme() == 'file': pageId = url.fileName() self.navigate(pageId) self.tabSelected(1) elif url.scheme() == 'http' or url.scheme() == 'https': self.browser.setUrl(url) def showMessage(self, message): self.parent().statusBar.showMessage(message, 3000) def navigate(self, pageId): """Assumption: pageId is sub page of current page""" self.l.debug('Navigating to sub page "{}"'.format(pageId)) self.editorWidget.save() self.browserWidget.navigate(pageId) # Will implicitly load the page def navigateDirect(self, pageId): """Assumption: pageId is NOT sub page of current page. Hence we need to let the browser point to the first occurrence of the page.""" self.l.debug('Navigating directly to "{}"'.format(pageId)) self.editorWidget.save() self.browserWidget.navigateDirect(pageId) # Will implicitly load the page def itemSelected(self): treeNode = self.browserWidget.currentItem self.l.debug('Selected tree node: {}'.format(treeNode)) pageId = treeNode.getPageId() notepad = treeNode.getNotepad() self.editorWidget.setEnabled(True) self.editorWidget.save() self.editorWidget.load(notepad, pageId) self.updateLinkLists(notepad, pageId) def updateLinkLists(self, notepad, pageId): linksTo = notepad.getChildPages(pageId) linksFrom = notepad.getParentPages(pageId) self.toLinksWidget.setContents(linksTo) self.fromLinksWidget.setContents(linksFrom) def tabSelected(self, index): if index == self.editTabIdx: pass elif index == self.webTabIdx: self.activateWebView() elif index == self.pdfTabIdx: pass elif index == self.structureTabIdx: self.activateStructureView() elif index == self.xmlTabIdx: self.activateXMLView() elif index == self.htmlTabIdx: self.activateHTMLView() def activateWebView(self): exporter = HTMLExporter(self.editorWidget.page.getPageDir()) self.htmlView.setPlainText(exporter.getHtmlString(self.editorWidget.editView.document())) ########### get URL for the stylesheet and for the base URL webpageCSS = pkg_resources.resource_string(data.__name__, 'webpage.css') print("webpage.css file: {} - {}".format(webpageCSS, type(webpageCSS))) mypath = os.getcwd() mypath = mypath.replace('\\', '/') baseURL = QUrl('file:///{}/'.format(mypath)) # The location must be either a path on the local filesystem, or a # data URL with UTF-8 and Base64 encoded data, such as: # "data:text/css;charset=utf-8;base64,cCB7IGJhY2tncm91bmQtY29sb3I6IHJlZCB9Ow==" # BASE64 works on bytes!! import base64 cssData = base64.b64encode(webpageCSS) cssData = cssData.decode('utf-8') cssDataUrl = 'data:text/css;charset=utf-8;base64,{}'.format(cssData) print("webpage.css base64: {}".format(cssDataUrl )) # cssDataUrl = QUrl('data:text/css;charset=utf-8;base64,{}'.format(cssData)) # 'file:///{}/webpage.css'.format(mypath)) ########### self.browser.settings().setUserStyleSheetUrl(QUrl(cssDataUrl)) self.browser.setHtml(self.htmlView.toPlainText(), baseURL) def activateStructureView(self): self.textView.clear() doc = self.editorWidget.editView.document() traversal = TextDocumentTraversal() tree = traversal.traverse(doc) sp = StructurePrinter(tree, self.textView.insertPlainText) sp.traverse() def activateXMLView(self): exporter = XMLExporter(self.editorWidget.page.getPageDir(), None) self.customView.setPlainText(exporter.getXmlString(self.editorWidget.editView.document())) def activateHTMLView(self): exporter = HTMLExporter(self.editorWidget.page.getPageDir()) self.htmlView.setPlainText(exporter.getHtmlString(self.editorWidget.editView.document()))
class QueryWidget(QWidget): editorModified = pyqtSignal(bool) def __init__(self): super(QueryWidget, self).__init__() box = QVBoxLayout(self) box.setContentsMargins(0, 0, 0, 0) self._vsplitter = QSplitter(Qt.Vertical) self._hsplitter = QSplitter(Qt.Horizontal) self._result_list = lateral_widget.LateralWidget() self._result_list.header().hide() self._hsplitter.addWidget(self._result_list) self._stack_tables = QStackedWidget() self._hsplitter.addWidget(self._stack_tables) self.relations = {} self._query_editor = editor.Editor() # Editor connections self._query_editor.customContextMenuRequested.connect( self.__show_context_menu) self._query_editor.modificationChanged[bool].connect( self.__editor_modified) self._query_editor.undoAvailable[bool].connect( self.__on_undo_available) self._query_editor.redoAvailable[bool].connect( self.__on_redo_available) self._query_editor.copyAvailable[bool].connect( self.__on_copy_available) self._vsplitter.addWidget(self._query_editor) self._vsplitter.addWidget(self._hsplitter) box.addWidget(self._vsplitter) # Connections self._result_list.itemClicked.connect( lambda index: self._stack_tables.setCurrentIndex( self._result_list.row())) self._result_list.itemDoubleClicked.connect( self.show_relation) def __show_context_menu(self, point): popup_menu = self._query_editor.createStandardContextMenu() undock_editor = QAction(self.tr("Undock"), self) popup_menu.insertAction(popup_menu.actions()[0], undock_editor) popup_menu.insertSeparator(popup_menu.actions()[1]) undock_editor.triggered.connect(self.__undock_editor) popup_menu.exec_(self.mapToGlobal(point)) def __undock_editor(self): new_editor = editor.Editor() actual_doc = self._query_editor.document() new_editor.setDocument(actual_doc) new_editor.resize(900, 400) # Set text cursor tc = self._query_editor.textCursor() new_editor.setTextCursor(tc) # Set title db = Pireal.get_service("central").get_active_db() qc = db.query_container new_editor.setWindowTitle(qc.tab_text(qc.current_index())) new_editor.show() def __on_undo_available(self, value): """ Change state of undo action """ pireal = Pireal.get_service("pireal") action = pireal.get_action("undo_action") action.setEnabled(value) def __on_redo_available(self, value): """ Change state of redo action """ pireal = Pireal.get_service("pireal") action = pireal.get_action("redo_action") action.setEnabled(value) def __on_copy_available(self, value): """ Change states of cut and copy action """ cut_action = Pireal.get_action("cut_action") cut_action.setEnabled(value) copy_action = Pireal.get_action("copy_action") copy_action.setEnabled(value) def show_relation(self, item): central_widget = Pireal.get_service("central") table_widget = central_widget.get_active_db().table_widget rela = self.relations[item.name] dialog = QDialog(self) dialog.resize(700, 500) dialog.setWindowTitle(item.name) box = QVBoxLayout(dialog) box.setContentsMargins(5, 5, 5, 5) table = table_widget.create_table(rela) box.addWidget(table) hbox = QHBoxLayout() btn = QPushButton(self.tr("Ok")) btn.clicked.connect(dialog.close) hbox.addStretch() hbox.addWidget(btn) box.addLayout(hbox) dialog.show() def save_sizes(self): """ Save sizes of Splitters """ qsettings = QSettings(settings.SETTINGS_PATH, QSettings.IniFormat) qsettings.setValue('hsplitter_query_sizes', self._hsplitter.saveState()) qsettings.setValue('vsplitter_query_sizes', self._vsplitter.saveState()) def get_editor(self): return self._query_editor def __editor_modified(self, modified): self.editorModified.emit(modified) def showEvent(self, event): super(QueryWidget, self).showEvent(event) self._hsplitter.setSizes([1, self.width() / 3]) def clear_results(self): self._result_list.clear_items() i = self._stack_tables.count() while i >= 0: widget = self._stack_tables.widget(i) self._stack_tables.removeWidget(widget) if widget is not None: widget.deleteLater() i -= 1 def add_table(self, rela, rname): wtable = custom_table.Table() # Model model = QStandardItemModel() wtable.setModel(model) model.setHorizontalHeaderLabels(rela.header) for data in rela.content: nrow = model.rowCount() # wtable.insertRow(nrow) for col, text in enumerate(data): item = QStandardItem(text) item.setFlags(item.flags() & ~Qt.ItemIsEditable) model.setItem(nrow, col, item) index = self._stack_tables.addWidget(wtable) self._stack_tables.setCurrentIndex(index) self._result_list.add_item(rname, rela.count())
def __initUI__(self): # ---- TAB WIDGET # download weather data : splash.showMessage("Initializing download weather data...") self.tab_dwnld_data = DwnldWeatherWidget(self) self.tab_dwnld_data.set_workdir(self.projectdir) # gapfill weather data : splash.showMessage("Initializing gapfill weather data...") self.tab_fill_weather_data = GapFillWeatherGUI(self) self.tab_fill_weather_data.set_workdir(self.projectdir) # hydrograph : splash.showMessage("Initializing plot hydrograph...") self.tab_hydrograph = HydroPrint.HydroprintGUI(self.dmanager) splash.showMessage("Initializing analyse hydrograph...") self.tab_hydrocalc = HydroCalc.WLCalc(self.dmanager) self.tab_hydrocalc.sig_new_mrc.connect( self.tab_hydrograph.mrc_wl_changed) self.tab_hydrocalc.rechg_eval_widget.sig_new_gluedf.connect( self.tab_hydrograph.glue_wl_changed) # ---- TABS ASSEMBLY self.tab_widget = TabWidget() self.tab_widget.addTab(self.tab_dwnld_data, 'Download Weather') self.tab_widget.addTab(self.tab_fill_weather_data, 'Gapfill Weather') self.tab_widget.addTab(self.tab_hydrograph, 'Plot Hydrograph') self.tab_widget.addTab(self.tab_hydrocalc, 'Analyze Hydrograph') self.tab_widget.setCornerWidget(self.pmanager) self.tab_widget.currentChanged.connect(self.sync_datamanagers) # ---- Main Console splash.showMessage("Initializing main window...") self.main_console = QTextEdit() self.main_console.setReadOnly(True) self.main_console.setLineWrapMode(QTextEdit.NoWrap) style = 'Regular' family = StyleDB().fontfamily size = self.whatPref.fontsize_console fontSS = ('font-style: %s;' 'font-size: %s;' 'font-family: %s;' ) % (style, size, family) self.main_console.setStyleSheet("QWidget{%s}" % fontSS) msg = '<font color=black>Thanks for using %s.</font>' % __appname__ self.write2console(msg) self.write2console('<font color=black>' 'Please report any bug or wishful feature at' ' [email protected].' '</font>') # ---- Signal Piping issuer = self.tab_dwnld_data issuer.ConsoleSignal.connect(self.write2console) issuer = self.tab_fill_weather_data issuer.ConsoleSignal.connect(self.write2console) issuer = self.tab_hydrograph issuer.ConsoleSignal.connect(self.write2console) # ---- Splitter Widget splitter = QSplitter(self) splitter.setOrientation(Qt.Vertical) splitter.addWidget(self.tab_widget) splitter.addWidget(self.main_console) splitter.setCollapsible(0, True) splitter.setStretchFactor(0, 100) # Forces initially the main_console to its minimal height: splitter.setSizes([100, 1]) # ---- Main Grid main_widget = QWidget() self.setCentralWidget(main_widget) mainGrid = QGridLayout(main_widget) mainGrid.addWidget(splitter, 0, 0) mainGrid.addWidget(self.tab_fill_weather_data.pbar, 1, 0) mainGrid.addWidget(self.tab_dwnld_data.pbar, 2, 0) mainGrid.addWidget( self.tab_hydrocalc.rechg_eval_widget.progressbar, 3, 0)
class HelpDialog(QObject, LogMixin): """Class implementing qthelp viewer dialog""" def __init__(self, qthelp_file, parent = None): """ Constructor of HelpDialog :param qthelp_file: full path to qthelp helpfile """ super(HelpDialog,self).__init__(parent) # instantiate help engine helpEngine = QHelpEngine(qthelp_file) helpEngine.setupData() self._helpEngine = helpEngine # base dialog widget self.ui = QDialog(None, QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowMinMaxButtonsHint | QtCore.Qt.WindowCloseButtonHint ) self.ui.setWindowTitle("HelpViewer") self.ui.setWindowIcon(QIcon(":/images/prog_icons/help/help.ico")) # Create webview for help information # and assign a custom URL scheme handler for scheme "qthelp) self._wv = QWebEngineView(self.ui) self._urlschemehandler = HelpSchemeHandler(self._helpEngine, self._wv.page().profile()) self._wv.page().profile().installUrlSchemeHandler(b'qthelp', self._urlschemehandler) # get help content overview widget self._helpContent = self._helpEngine.contentWidget() self._helpIndex = self._helpEngine.indexWidget() self._helpSearchQuery = self._helpEngine.searchEngine().queryWidget() self._helpSearchResult = self._helpEngine.searchEngine().resultWidget() self._se = self._helpEngine.searchEngine() self._se.reindexDocumentation() self._helpSearchQuery.search.connect(self.search) # create QSplitter self._splitterMain = QSplitter(QtCore.Qt.Vertical) self._splitterMain.setOpaqueResize(False) self._splitterSearch = QSplitter(QtCore.Qt.Horizontal) self._splitterSearch.setOpaqueResize(False) self._splitterUpper = QSplitter(QtCore.Qt.Horizontal) self._splitterUpper.setOpaqueResize(False) self._splitterLower = QSplitter(QtCore.Qt.Horizontal) self._splitterLower.setOpaqueResize(False) # create horzLayout self._horzLayoutSearch = QHBoxLayout() self._horzLayoutUpper = QHBoxLayout() self._horzLayoutLower = QHBoxLayout() # create vertLayout self._vertLayout = QVBoxLayout() # main widgets self._upperWidget = QWidget() self._lowerWidget = QWidget() self._btnReset = QPushButton() self._btnReset.setMaximumHeight(23) self._btnReset.setMaximumWidth(100) # build search structure self._splitterSearch.insertWidget(0, self._helpSearchQuery) self._splitterSearch.insertWidget(1, self._btnReset) # build upper inner structure self._splitterUpper.insertWidget(0, self._helpContent) self._splitterUpper.insertWidget(1, self._wv) self._horzLayoutUpper.addWidget(self._splitterUpper) self._upperWidget.setLayout(self._horzLayoutUpper) # build lower inner structure self._splitterLower.insertWidget(0, self._helpIndex) self._splitterLower.insertWidget(1, self._helpSearchResult) self._horzLayoutLower.addWidget(self._splitterLower) self._lowerWidget.setLayout(self._horzLayoutLower) # build outer structure self._splitterMain.insertWidget(0, self._splitterSearch) self._splitterMain.insertWidget(1, self._upperWidget) self._splitterMain.insertWidget(2, self._lowerWidget) self._helpSearchResult.hide() self._btnReset.hide() self._vertLayout.addWidget(self._splitterMain) self.ui.setLayout(self._vertLayout) # set splitter width w = self._splitterUpper.geometry().width() self._splitterUpper.setSizes([w*(1/4), w*(3/4)]) w = self._splitterLower.geometry().width() self._splitterLower.setSizes([w*(1/5), w*(4/5)]) h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/9), h*(7/9), h*(1/9)]) self._helpContent.linkActivated.connect(self._wv.setUrl) self._helpIndex.linkActivated.connect(self._wv.setUrl) self._helpSearchResult.requestShowLink.connect(self._wv.setUrl) self._se.searchingFinished.connect(self.showResults) self._btnReset.clicked.connect(self.resetResult) self.retranslateMsg() def retranslateMsg(self): self.logger.debug("Retranslating further messages...") self._btnReset.setText(translate("HelpViewer", "Reset")) self._btnReset.setText(translate("HelpViewer", "Search")) def search(self): """Initiate qthelp search""" self._se.search(self._helpSearchQuery.query()) def showResults(self): """Show search results, if any""" if self._se.hitCount() > 0: self._helpIndex.hide() h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/3), h*(1/3), h*(1/3)]) self._helpSearchResult.show() self._btnReset.show() def resetResult(self): """Reset search result widget""" self._helpSearchResult.hide() self._btnReset.hide() self._helpIndex.show() h = self._splitterMain.geometry().height() self._splitterMain.setSizes([h*(1/9), h*(7/9), h*(1/9)])
class EntryView(BaseTransactionView): def _setup(self): self._setupUi() self.etable = EntryTable(self.model.etable, view=self.tableView) self.efbar = EntryFilterBar(model=self.model.filter_bar, view=self.filterBar) self.bgraph = Chart(self.model.bargraph, view=self.barGraphView) self.lgraph = Chart(self.model.balgraph, view=self.lineGraphView) self._setupColumns() # Can only be done after the model has been connected self.reconciliationButton.clicked.connect(self.model.toggle_reconciliation_mode) def _setupUi(self): self.resize(483, 423) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setSpacing(0) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setSpacing(0) self.filterBar = RadioBox(self) sizePolicy = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.filterBar.sizePolicy().hasHeightForWidth()) self.filterBar.setSizePolicy(sizePolicy) self.horizontalLayout.addWidget(self.filterBar) self.horizontalLayout.addItem(horizontalSpacer()) self.reconciliationButton = QPushButton(tr("Reconciliation")) self.reconciliationButton.setCheckable(True) self.horizontalLayout.addWidget(self.reconciliationButton) self.verticalLayout.addLayout(self.horizontalLayout) self.splitterView = QSplitter() self.splitterView.setOrientation(Qt.Vertical) self.splitterView.setChildrenCollapsible(False) self.tableView = TableView(self) self.tableView.setAcceptDrops(True) self.tableView.setEditTriggers(QAbstractItemView.DoubleClicked|QAbstractItemView.EditKeyPressed) self.tableView.setDragEnabled(True) self.tableView.setDragDropMode(QAbstractItemView.InternalMove) self.tableView.setSelectionBehavior(QAbstractItemView.SelectRows) self.tableView.setSortingEnabled(True) self.tableView.horizontalHeader().setHighlightSections(False) self.tableView.horizontalHeader().setMinimumSectionSize(18) self.tableView.verticalHeader().setVisible(False) self.tableView.verticalHeader().setDefaultSectionSize(18) self.splitterView.addWidget(self.tableView) self.graphView = QStackedWidget(self) sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.graphView.sizePolicy().hasHeightForWidth()) self.graphView.setSizePolicy(sizePolicy) self.graphView.setMinimumSize(0, 200) self.lineGraphView = LineGraphView() self.graphView.addWidget(self.lineGraphView) self.barGraphView = BarGraphView() self.graphView.addWidget(self.barGraphView) self.splitterView.addWidget(self.graphView) self.graphView.setCurrentIndex(1) self.splitterView.setStretchFactor(0, 1) self.splitterView.setStretchFactor(1, 0) self.verticalLayout.addWidget(self.splitterView) def _setupColumns(self): h = self.tableView.horizontalHeader() h.setSectionsMovable(True) # column drag & drop reorder # --- QWidget override def setFocus(self): self.etable.view.setFocus() # --- Public def fitViewsForPrint(self, viewPrinter): hidden = self.model.mainwindow.hidden_areas viewPrinter.fitTable(self.etable) if PaneArea.BottomGraph not in hidden: viewPrinter.fit(self.graphView.currentWidget(), 300, 150, expandH=True, expandV=True) def restoreSubviewsSize(self): graphHeight = self.model.graph_height_to_restore if graphHeight: splitterHeight = self.splitterView.height() sizes = [splitterHeight-graphHeight, graphHeight] self.splitterView.setSizes(sizes) # --- model --> view def refresh_reconciliation_button(self): if self.model.can_toggle_reconciliation_mode: self.reconciliationButton.setEnabled(True) self.reconciliationButton.setChecked(self.model.reconciliation_mode) else: self.reconciliationButton.setEnabled(False) self.reconciliationButton.setChecked(False) def show_bar_graph(self): self.graphView.setCurrentIndex(1) def show_line_graph(self): self.graphView.setCurrentIndex(0) def update_visibility(self): hidden = self.model.mainwindow.hidden_areas self.graphView.setHidden(PaneArea.BottomGraph in hidden)
class SubTabWidget(QWidget): _tabChanged = pyqtSignal(int, name = "tabChanged") def __init__(self, subtitleData, videoWidget, parent = None): super(SubTabWidget, self).__init__(parent) self._subtitleData = subtitleData self.__initTabWidget(videoWidget) def __initTabWidget(self, videoWidget): settings = SubSettings() mainLayout = QVBoxLayout(self) mainLayout.setContentsMargins(0, 0, 0, 0) mainLayout.setSpacing(0) #TabBar self.tabBar = QTabBar(self) # Splitter (bookmarks + pages) self.splitter = QSplitter(self) self.splitter.setObjectName("sidebar_splitter") self._toolbox = ToolBox(self._subtitleData, self) self._toolbox.setObjectName("sidebar") self._toolbox.setMinimumWidth(100) self._toolbox.addTool(Details(self._subtitleData, self)) self._toolbox.addTool(Synchronizer(videoWidget, self._subtitleData, self)) self._toolbox.addTool(History(self)) self.rightWidget = QWidget() rightLayout = QGridLayout() rightLayout.setContentsMargins(0, 0, 0, 0) self.rightWidget.setLayout(rightLayout) self._mainTab = FileList(_("Subtitles"), self._subtitleData, self) self.pages = QStackedWidget(self) rightLayout.addWidget(self.pages, 0, 0) self.tabBar.addTab(self._mainTab.name) self.pages.addWidget(self._mainTab) self.splitter.addWidget(self._toolbox) self.splitter.addWidget(self.rightWidget) self.__drawSplitterHandle(1) # Setting widgets mainLayout.addWidget(self.tabBar) mainLayout.addWidget(self.splitter) # Widgets settings self.tabBar.setMovable(True) self.tabBar.setTabsClosable(True) self.tabBar.setExpanding(False) # Don't resize left panel if it's not needed leftWidgetIndex = self.splitter.indexOf(self._toolbox) rightWidgetIndex = self.splitter.indexOf(self.rightWidget) self.splitter.setStretchFactor(leftWidgetIndex, 0) self.splitter.setStretchFactor(rightWidgetIndex, 1) self.splitter.setCollapsible(leftWidgetIndex, False) self.splitter.setSizes([250]) # Some signals self.tabBar.currentChanged.connect(self.showTab) self.tabBar.tabCloseRequested.connect(self.closeTab) self.tabBar.tabMoved.connect(self.moveTab) self._mainTab.requestOpen.connect(self.openTab) self._mainTab.requestRemove.connect(self.removeFile) self.tabChanged.connect(lambda i: self._toolbox.setContentFor(self.tab(i))) self.setLayout(mainLayout) def __addTab(self, filePath): """Returns existing tab index. Creates a new one if it isn't opened and returns its index otherwise.""" for i in range(self.tabBar.count()): widget = self.pages.widget(i) if not widget.isStatic and filePath == widget.filePath: return i tab = SubtitleEditor(filePath, self._subtitleData, self) newIndex = self.tabBar.addTab(self._createTabName(tab.name, tab.history.isClean())) tab.history.cleanChanged.connect( lambda clean: self._cleanStateForFileChanged(filePath, clean)) self.pages.addWidget(tab) return newIndex def __drawSplitterHandle(self, index): splitterHandle = self.splitter.handle(index) splitterLayout = QVBoxLayout(splitterHandle) splitterLayout.setSpacing(0) splitterLayout.setContentsMargins(0, 0, 0, 0) line = QFrame(splitterHandle) line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) splitterLayout.addWidget(line) splitterHandle.setLayout(splitterLayout) def _createTabName(self, name, cleanState): if cleanState is True: return name else: return "%s +" % name def _cleanStateForFileChanged(self, filePath, cleanState): page = self.tabByPath(filePath) if page is not None: for i in range(self.tabBar.count()): if self.tabBar.tabText(i)[:len(page.name)] == page.name: self.tabBar.setTabText(i, self._createTabName(page.name, cleanState)) return def saveWidgetState(self, settings): settings.setState(self.splitter, self.splitter.saveState()) settings.setHidden(self._toolbox, self._toolbox.isHidden()) def restoreWidgetState(self, settings): self.showPanel(not settings.getHidden(self._toolbox)) splitterState = settings.getState(self.splitter) if not splitterState.isEmpty(): self.splitter.restoreState(settings.getState(self.splitter)) @pyqtSlot(str, bool) def openTab(self, filePath, background=False): if self._subtitleData.fileExists(filePath): tabIndex = self.__addTab(filePath) if background is False: self.showTab(tabIndex) else: log.error(_("SubtitleEditor not created for %s!" % filePath)) @pyqtSlot(str) def removeFile(self, filePath): tab = self.tabByPath(filePath) command = RemoveFile(filePath) if tab is not None: index = self.pages.indexOf(tab) if self.closeTab(index): self._subtitleData.execute(command) else: self._subtitleData.execute(command) @pyqtSlot(int) def closeTab(self, index): tab = self.tab(index) if tab.canClose(): widgetToRemove = self.pages.widget(index) self.tabBar.removeTab(index) self.pages.removeWidget(widgetToRemove) widgetToRemove.deleteLater() return True return False def count(self): return self.tabBar.count() def currentIndex(self): return self.tabBar.currentIndex() def currentPage(self): return self.pages.currentWidget() @pyqtSlot(int, int) def moveTab(self, fromIndex, toIndex): fromWidget = self.pages.widget(fromIndex) toWidget = self.pages.widget(toIndex) if fromWidget.isStatic or toWidget.isStatic: self.tabBar.blockSignals(True) # signals would cause infinite recursion self.tabBar.moveTab(toIndex, fromIndex) self.tabBar.blockSignals(False) return else: self.pages.removeWidget(fromWidget) self.pages.removeWidget(toWidget) if fromIndex < toIndex: self.pages.insertWidget(fromIndex, toWidget) self.pages.insertWidget(toIndex, fromWidget) else: self.pages.insertWidget(toIndex, fromWidget) self.pages.insertWidget(fromIndex, toWidget) # Hack # Qt changes tabs during mouse drag and dropping. The next line is added # to prevent it. self.showTab(self.tabBar.currentIndex()) @pyqtSlot(int) def showTab(self, index): showWidget = self.pages.widget(index) if showWidget: self.pages.setCurrentWidget(showWidget) self.tabBar.blockSignals(True) self.tabBar.setCurrentIndex(index) self.tabBar.blockSignals(False) # Try to update current tab. showWidget.updateTab() self._tabChanged.emit(index) def showPanel(self, val): if val is True: self._toolbox.show() else: self._toolbox.hide() def togglePanel(self): if self._toolbox.isHidden(): self._toolbox.show() else: self._toolbox.hide() def tab(self, index): return self.pages.widget(index) def tabByPath(self, path): for i in range(self.pages.count()): page = self.tab(i) if not page.isStatic and page.filePath == path: return page return None @property def fileList(self): return self._mainTab
class Listspace(QSplitter, ViewManager): """ Class implementing the listspace viewmanager class. @signal changeCaption(str) emitted if a change of the caption is necessary @signal editorChanged(str) emitted when the current editor has changed @signal editorChangedEd(Editor) emitted when the current editor has changed @signal lastEditorClosed() emitted after the last editor window was closed @signal editorOpened(str) emitted after an editor window was opened @signal editorOpenedEd(Editor) emitted after an editor window was opened @signal editorClosed(str) emitted just before an editor window gets closed @signal editorClosedEd(Editor) emitted just before an editor window gets closed @signal editorRenamed(str) emitted after an editor was renamed @signal editorRenamedEd(Editor) emitted after an editor was renamed @signal editorSaved(str) emitted after an editor window was saved @signal editorSavedEd(Editor) emitted after an editor window was saved @signal checkActions(Editor) emitted when some actions should be checked for their status @signal cursorChanged(Editor) emitted after the cursor position of the active window has changed @signal breakpointToggled(Editor) emitted when a breakpoint is toggled. @signal bookmarkToggled(Editor) emitted when a bookmark is toggled. @signal syntaxerrorToggled(Editor) emitted when a syntax error is toggled. @signal previewStateChanged(bool) emitted to signal a change in the preview state @signal editorLanguageChanged(Editor) emitted to signal a change of an editors language @signal editorTextChanged(Editor) emitted to signal a change of an editor's text @signal editorLineChanged(str,int) emitted to signal a change of an editor's current line (line is given one based) """ changeCaption = pyqtSignal(str) editorChanged = pyqtSignal(str) editorChangedEd = pyqtSignal(Editor) lastEditorClosed = pyqtSignal() editorOpened = pyqtSignal(str) editorOpenedEd = pyqtSignal(Editor) editorClosed = pyqtSignal(str) editorClosedEd = pyqtSignal(Editor) editorRenamed = pyqtSignal(str) editorRenamedEd = pyqtSignal(Editor) editorSaved = pyqtSignal(str) editorSavedEd = pyqtSignal(Editor) checkActions = pyqtSignal(Editor) cursorChanged = pyqtSignal(Editor) breakpointToggled = pyqtSignal(Editor) bookmarkToggled = pyqtSignal(Editor) syntaxerrorToggled = pyqtSignal(Editor) previewStateChanged = pyqtSignal(bool) editorLanguageChanged = pyqtSignal(Editor) editorTextChanged = pyqtSignal(Editor) editorLineChanged = pyqtSignal(str, int) def __init__(self, parent): """ Constructor @param parent parent widget (QWidget) """ self.stacks = [] QSplitter.__init__(self, parent) ViewManager.__init__(self) self.setChildrenCollapsible(False) self.viewlist = QListWidget(self) policy = self.viewlist.sizePolicy() policy.setHorizontalPolicy(QSizePolicy.Ignored) self.viewlist.setSizePolicy(policy) self.addWidget(self.viewlist) self.viewlist.setContextMenuPolicy(Qt.CustomContextMenu) self.viewlist.currentRowChanged.connect(self.__showSelectedView) self.viewlist.customContextMenuRequested.connect(self.__showMenu) self.stackArea = QSplitter(self) self.stackArea.setChildrenCollapsible(False) self.addWidget(self.stackArea) self.stackArea.setOrientation(Qt.Vertical) stack = StackedWidget(self.stackArea) self.stackArea.addWidget(stack) self.stacks.append(stack) self.currentStack = stack stack.currentChanged.connect(self.__currentChanged) stack.installEventFilter(self) self.setSizes([int(self.width() * 0.2), int(self.width() * 0.8)]) # 20% for viewlist, 80% for the editors self.__inRemoveView = False self.__initMenu() self.contextMenuEditor = None self.contextMenuIndex = -1 def __initMenu(self): """ Private method to initialize the viewlist context menu. """ self.__menu = QMenu(self) self.__menu.addAction( UI.PixmapCache.getIcon("tabClose.png"), self.tr('Close'), self.__contextMenuClose) self.closeOthersMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("tabCloseOther.png"), self.tr("Close Others"), self.__contextMenuCloseOthers) self.__menu.addAction( self.tr('Close All'), self.__contextMenuCloseAll) self.__menu.addSeparator() self.saveMenuAct = self.__menu.addAction( UI.PixmapCache.getIcon("fileSave.png"), self.tr('Save'), self.__contextMenuSave) self.__menu.addAction( UI.PixmapCache.getIcon("fileSaveAs.png"), self.tr('Save As...'), self.__contextMenuSaveAs) self.__menu.addAction( UI.PixmapCache.getIcon("fileSaveAll.png"), self.tr('Save All'), self.__contextMenuSaveAll) self.__menu.addSeparator() self.openRejectionsMenuAct = self.__menu.addAction( self.tr("Open 'rejection' file"), self.__contextMenuOpenRejections) self.__menu.addSeparator() self.__menu.addAction( UI.PixmapCache.getIcon("print.png"), self.tr('Print'), self.__contextMenuPrintFile) self.__menu.addSeparator() self.copyPathAct = self.__menu.addAction( self.tr("Copy Path to Clipboard"), self.__contextMenuCopyPathToClipboard) def __showMenu(self, point): """ Private slot to handle the customContextMenuRequested signal of the viewlist. @param point position to open the menu at (QPoint) """ if self.editors: itm = self.viewlist.itemAt(point) if itm is not None: row = self.viewlist.row(itm) self.contextMenuEditor = self.editors[row] self.contextMenuIndex = row if self.contextMenuEditor: self.saveMenuAct.setEnabled( self.contextMenuEditor.isModified()) fileName = self.contextMenuEditor.getFileName() self.copyPathAct.setEnabled(bool(fileName)) if fileName: rej = "{0}.rej".format(fileName) self.openRejectionsMenuAct.setEnabled( os.path.exists(rej)) else: self.openRejectionsMenuAct.setEnabled(False) self.closeOthersMenuAct.setEnabled( self.viewlist.count() > 1) self.__menu.popup(self.viewlist.mapToGlobal(point)) def canCascade(self): """ Public method to signal if cascading of managed windows is available. @return flag indicating cascading of windows is available """ return False def canTile(self): """ Public method to signal if tiling of managed windows is available. @return flag indicating tiling of windows is available """ return False def canSplit(self): """ public method to signal if splitting of the view is available. @return flag indicating splitting of the view is available. """ return True def tile(self): """ Public method to tile the managed windows. """ pass def cascade(self): """ Public method to cascade the managed windows. """ pass def _removeAllViews(self): """ Protected method to remove all views (i.e. windows). """ self.viewlist.clear() for win in self.editors: for stack in self.stacks: if stack.hasEditor(win): stack.removeWidget(win) break win.closeIt() def _removeView(self, win): """ Protected method to remove a view (i.e. window). @param win editor window to be removed """ self.__inRemoveView = True ind = self.editors.index(win) itm = self.viewlist.takeItem(ind) if itm: del itm for stack in self.stacks: if stack.hasEditor(win): stack.removeWidget(win) break win.closeIt() self.__inRemoveView = False if ind > 0: ind -= 1 else: if len(self.editors) > 1: ind = 1 else: return stack.setCurrentWidget(stack.firstEditor()) self._showView(self.editors[ind].parent()) aw = self.activeWindow() fn = aw and aw.getFileName() or None if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) def _addView(self, win, fn=None, noName="", next=False): """ Protected method to add a view (i.e. window). @param win editor assembly to be added @param fn filename of this editor (string) @param noName name to be used for an unnamed editor (string) @param next flag indicating to add the view next to the current view (bool) """ editor = win.getEditor() if fn is None: if not noName: self.untitledCount += 1 noName = self.tr("Untitled {0}").format(self.untitledCount) self.viewlist.addItem(noName) editor.setNoName(noName) else: txt = os.path.basename(fn) if not QFileInfo(fn).isWritable(): txt = self.tr("{0} (ro)").format(txt) itm = QListWidgetItem(txt) itm.setToolTip(fn) self.viewlist.addItem(itm) self.currentStack.addWidget(win) self.currentStack.setCurrentWidget(win) editor.captionChanged.connect(self.__captionChange) editor.cursorLineChanged.connect(self.__cursorLineChanged) index = self.editors.index(editor) self.viewlist.setCurrentRow(index) editor.setFocus() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def __captionChange(self, cap, editor): """ Private method to handle caption change signals from the editor. Updates the listwidget text to reflect the new caption information. @param cap Caption for the editor (string) @param editor Editor to update the caption for """ fn = editor.getFileName() if fn: self.setEditorName(editor, fn) def __cursorLineChanged(self, lineno): """ Private slot to handle a change of the current editor's cursor line. @param lineno line number of the current editor's cursor (zero based) """ editor = self.sender() if editor: fn = editor.getFileName() if fn: self.editorLineChanged.emit(fn, lineno + 1) def _showView(self, win, fn=None): """ Protected method to show a view (i.e. window). @param win editor assembly to be shown @param fn filename of this editor (string) """ editor = win.getEditor() for stack in self.stacks: if stack.hasEditor(editor): stack.setCurrentWidget(win) self.currentStack = stack break index = self.editors.index(editor) self.viewlist.setCurrentRow(index) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) self.editorChanged.emit(fn) self.editorLineChanged.emit(fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) def __showSelectedView(self, row): """ Private slot called to show a view selected in the list. @param row row number of the item clicked on (integer) """ if row != -1: self._showView(self.editors[row].parent()) self._checkActions(self.editors[row]) def activeWindow(self): """ Public method to return the active (i.e. current) window. @return reference to the active editor """ return self.currentStack.currentWidget() def showWindowMenu(self, windowMenu): """ Public method to set up the viewmanager part of the Window menu. @param windowMenu reference to the window menu """ pass def _initWindowActions(self): """ Protected method to define the user interface actions for window handling. """ pass def setEditorName(self, editor, newName): """ Public method to change the displayed name of the editor. @param editor editor window to be changed @param newName new name to be shown (string) """ if newName: currentRow = self.viewlist.currentRow() index = self.editors.index(editor) txt = os.path.basename(newName) if not QFileInfo(newName).isWritable(): txt = self.tr("{0} (ro)").format(txt) itm = self.viewlist.item(index) itm.setText(txt) itm.setToolTip(newName) self.viewlist.setCurrentRow(currentRow) self.changeCaption.emit(newName) def _modificationStatusChanged(self, m, editor): """ Protected slot to handle the modificationStatusChanged signal. @param m flag indicating the modification status (boolean) @param editor editor window changed """ currentRow = self.viewlist.currentRow() index = self.editors.index(editor) keys = [] if m: keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") self.viewlist.item(index).setIcon( UI.PixmapCache.getCombinedIcon(keys)) self.viewlist.setCurrentRow(currentRow) self._checkActions(editor) def _syntaxErrorToggled(self, editor): """ Protected slot to handle the syntaxerrorToggled signal. @param editor editor that sent the signal """ currentRow = self.viewlist.currentRow() index = self.editors.index(editor) keys = [] if editor.isModified(): keys.append("fileModified.png") if editor.hasSyntaxErrors(): keys.append("syntaxError22.png") elif editor.hasWarnings(): keys.append("warning22.png") if not keys: keys.append("empty.png") self.viewlist.item(index).setIcon( UI.PixmapCache.getCombinedIcon(keys)) self.viewlist.setCurrentRow(currentRow) ViewManager._syntaxErrorToggled(self, editor) def addSplit(self): """ Public method used to split the current view. """ stack = StackedWidget(self.stackArea) stack.show() self.stackArea.addWidget(stack) self.stacks.append(stack) self.currentStack = stack stack.currentChanged.connect(self.__currentChanged) stack.installEventFilter(self) if self.stackArea.orientation() == Qt.Horizontal: size = self.stackArea.width() else: size = self.stackArea.height() self.stackArea.setSizes( [int(size / len(self.stacks))] * len(self.stacks)) self.splitRemoveAct.setEnabled(True) self.nextSplitAct.setEnabled(True) self.prevSplitAct.setEnabled(True) def removeSplit(self): """ Public method used to remove the current split view. @return flag indicating successfull removal """ if len(self.stacks) > 1: stack = self.currentStack res = True savedEditors = stack.editors[:] for editor in savedEditors: res &= self.closeEditor(editor) if res: try: i = self.stacks.index(stack) except ValueError: return True if i == len(self.stacks) - 1: i -= 1 self.stacks.remove(stack) stack.close() self.currentStack = self.stacks[i] if len(self.stacks) == 1: self.splitRemoveAct.setEnabled(False) self.nextSplitAct.setEnabled(False) self.prevSplitAct.setEnabled(False) return True return False def getSplitOrientation(self): """ Public method to get the orientation of the split view. @return orientation of the split (Qt.Horizontal or Qt.Vertical) """ return self.stackArea.orientation() def setSplitOrientation(self, orientation): """ Public method used to set the orientation of the split view. @param orientation orientation of the split (Qt.Horizontal or Qt.Vertical) """ self.stackArea.setOrientation(orientation) def nextSplit(self): """ Public slot used to move to the next split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.stacks.index(self.currentStack) + 1 if ind == len(self.stacks): ind = 0 self.currentStack = self.stacks[ind] if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() index = self.editors.index(self.currentStack.currentWidget()) self.viewlist.setCurrentRow(index) def prevSplit(self): """ Public slot used to move to the previous split. """ aw = self.activeWindow() _hasFocus = aw and aw.hasFocus() ind = self.stacks.index(self.currentStack) - 1 if ind == -1: ind = len(self.stacks) - 1 self.currentStack = self.stacks[ind] if _hasFocus: aw = self.activeWindow() if aw: aw.setFocus() index = self.editors.index(self.currentStack.currentWidget()) self.viewlist.setCurrentRow(index) def __contextMenuClose(self): """ Private method to close the selected editor. """ if self.contextMenuEditor: self.closeEditorWindow(self.contextMenuEditor) def __contextMenuCloseOthers(self): """ Private method to close the other editors. """ index = self.contextMenuIndex for i in list(range(self.viewlist.count() - 1, index, -1)) + \ list(range(index - 1, -1, -1)): editor = self.editors[i] self.closeEditorWindow(editor) def __contextMenuCloseAll(self): """ Private method to close all editors. """ savedEditors = self.editors[:] for editor in savedEditors: self.closeEditorWindow(editor) def __contextMenuSave(self): """ Private method to save the selected editor. """ if self.contextMenuEditor: self.saveEditorEd(self.contextMenuEditor) def __contextMenuSaveAs(self): """ Private method to save the selected editor to a new file. """ if self.contextMenuEditor: self.saveAsEditorEd(self.contextMenuEditor) def __contextMenuSaveAll(self): """ Private method to save all editors. """ self.saveEditorsList(self.editors) def __contextMenuOpenRejections(self): """ Private slot to open a rejections file associated with the selected editor. """ if self.contextMenuEditor: fileName = self.contextMenuEditor.getFileName() if fileName: rej = "{0}.rej".format(fileName) if os.path.exists(rej): self.openSourceFile(rej) def __contextMenuPrintFile(self): """ Private method to print the selected editor. """ if self.contextMenuEditor: self.printEditor(self.contextMenuEditor) def __contextMenuCopyPathToClipboard(self): """ Private method to copy the file name of the selected editor to the clipboard. """ if self.contextMenuEditor: fn = self.contextMenuEditor.getFileName() if fn: cb = QApplication.clipboard() cb.setText(fn) def __currentChanged(self, index): """ Private slot to handle the currentChanged signal. @param index index of the current editor """ if index == -1 or not self.editors: return editor = self.activeWindow() if editor is None: return self._checkActions(editor) editor.setFocus() fn = editor.getFileName() if fn: self.changeCaption.emit(fn) if not self.__inRemoveView: self.editorChanged.emit(fn) self.editorLineChanged.emit( fn, editor.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(editor) cindex = self.editors.index(editor) self.viewlist.setCurrentRow(cindex) def eventFilter(self, watched, event): """ Public method called to filter the event queue. @param watched the QObject being watched @param event the event that occurred @return flag indicating, if we handled the event """ if event.type() == QEvent.MouseButtonPress and \ not event.button() == Qt.RightButton: switched = True if isinstance(watched, QStackedWidget): switched = watched is not self.currentStack self.currentStack = watched elif isinstance(watched, QScintilla.Editor.Editor): for stack in self.stacks: if stack.hasEditor(watched): switched = stack is not self.currentStack self.currentStack = stack break currentWidget = self.currentStack.currentWidget() if currentWidget: index = self.editors.index(currentWidget) self.viewlist.setCurrentRow(index) aw = self.activeWindow() if aw is not None: self._checkActions(aw) aw.setFocus() fn = aw.getFileName() if fn: self.changeCaption.emit(fn) if switched: self.editorChanged.emit(fn) self.editorLineChanged.emit( fn, aw.getCursorPosition()[0] + 1) else: self.changeCaption.emit("") self.editorChangedEd.emit(aw) return False
class ParamModWgt(QWidget): def __init__(self, parent=None): super().__init__(parent) self.main_window = parent self.buildRequiredTagsGB() # Widgets self.newParamBtn = QPushButton("New") self.deleteParamBtn = QPushButton("Delete") self.paramSaveAnnotBtn = QPushButton("Save") buttonWidget = QWidget(self) self.existingParamsGB = QGroupBox("Existing parameters", self) self.paramListTblWdg = QTableView() self.paramListModel = ParameterListModel(parent=self) self.paramListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows) self.paramListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection) self.paramListTblWdg.setModel(self.paramListModel) self.paramListTblWdg.setColumnWidth(0, 150) self.paramListTblWdg.setColumnWidth(1, 350) self.relationWgt = ParamRelationWgt(parent) self.newParamsGB = QGroupBox("Parameter details", self) self.resultTypeCbo = QComboBox(self) self.isExpProp = QCheckBox("is an experimental property", self) self.resultTypeCbo.addItems(["point value", "function", "numerical trace"]) self.singleValueParamWgt = ParamValueWgt(parent) self.functionParamWgt = ParamFunctionWgt(parent) self.traceParamWgt = ParamTraceWgt(parent) self.functionParamWgt.mainWgt = self self.paramModStack = QStackedWidget(self) self.paramModStack.addWidget(self.singleValueParamWgt) self.paramModStack.addWidget(self.functionParamWgt) self.paramModStack.addWidget(self.traceParamWgt) # Signals selectionModel = self.paramListTblWdg.selectionModel() selectionModel.selectionChanged.connect(self.selectedParameterChanged) self.newParamBtn.clicked.connect(self.newParameter) self.deleteParamBtn.clicked.connect(self.deleteParameter) self.paramSaveAnnotBtn.clicked.connect(self.saveParameter) self.resultTypeCbo.currentIndexChanged.connect(self.paramModStack.setCurrentIndex) self.singleValueParamWgt.paramTypeSelected.connect(self.newParamTypeSelected) self.functionParamWgt.paramTypeSelected.connect(self.newParamTypeSelected) self.traceParamWgt.paramTypeSelected.connect(self.newParamTypeSelected) # Layout buttonLayout = QVBoxLayout(buttonWidget) buttonLayout.addWidget(self.paramSaveAnnotBtn) buttonLayout.addWidget(self.deleteParamBtn) buttonLayout.addWidget(self.newParamBtn) existGrid = QHBoxLayout(self.existingParamsGB) existGrid.addWidget(buttonWidget) existGrid.addWidget(self.paramListTblWdg) newGrid = QGridLayout(self.newParamsGB) newGrid.addWidget(QLabel("Result type"), 0, 0) newGrid.addWidget(self.resultTypeCbo, 0, 1) newGrid.addWidget(self.isExpProp, 0, 2) newGrid.addWidget(self.paramModStack, 1, 0, 1, 3) newGrid.addWidget(self.relationWgt, 1, 3) layout = QVBoxLayout(self) self.rootLayout = QSplitter(Qt.Vertical, self) self.rootLayout.setOrientation(Qt.Vertical) self.rootLayout.addWidget(self.existingParamsGB) self.rootLayout.addWidget(self.newParamsGB) self.rootLayout.addWidget(self.requireTagGB) layout.addWidget(self.rootLayout) # Initial behavior self.newParamBtn.setEnabled(True) self.deleteParamBtn.setEnabled(False) self.paramSaveAnnotBtn.setEnabled(False) self.additionMode = False self.newParamsGB.setEnabled(False) def setRootLayoutSizes(self, sizes): self.rootLayout.setSizes(sizes) def viewParameter(self, parameter): row = -1 for row, param in enumerate(self.paramListModel.parameterList): if param.id == parameter.id: break assert(row > -1) self.paramListTblWdg.selectRow(row) @pyqtSlot(str) def newParamTypeSelected(self, paramName): self.requiredTagsListModel.clear() self.requiredTagsListModel.refresh() paramType = getParameterTypeFromName(paramName) if paramType is None: raise ValueError("Parameter type with name '" + paramName + "' was not found.") for reqTag in paramType.requiredTags: self.requiredTagsListModel.addTag(reqTag.id, reqTag.name, reqTag.id, reqTag.name) self.requiredTagsListModel.refresh() def buildRequiredTagsGB(self): # Widgets self.requireTagGB = QGroupBox("Required tag categories", self) self.requiredTagsListTblWdg = RequiredTagsTableView() self.requiredTagsListModel = RequiredTagsListModel(parent=self) self.requiredTagsListTblWdg.setSelectionBehavior(QAbstractItemView.SelectRows) self.requiredTagsListTblWdg.setSelectionMode(QAbstractItemView.SingleSelection) self.requiredTagsListTblWdg.setModel(self.requiredTagsListModel) self.requiredTagsListTblWdg.setColumnWidth(0, 200) self.requiredTagsListTblWdg.setColumnWidth(1, 200) # Layout requiredTagLayout = QGridLayout(self.requireTagGB) requiredTagLayout.addWidget(self.requiredTagsListTblWdg, 0, 0, 4, 1) def newParameter(self): self.resultTypeCbo.setCurrentIndex(0) self.paramModStack.currentWidget().newParameter() self.singleValueParamWgt.newParameter() self.functionParamWgt.newParameter() self.traceParamWgt.newParameter() self.newParamsGB.setEnabled(True) self.paramListTblWdg.clearSelection() self.newParamBtn.setEnabled(False) self.deleteParamBtn.setEnabled(False) self.paramSaveAnnotBtn.setEnabled(True) self.isExpProp.setChecked(False) def saveParameter(self): relationship = self.relationWgt.getRelationship() # Get the ID of the modified parameter if we are modifying an existing # parameters if len(self.paramListTblWdg.selectionModel().selectedRows()) != 0: selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() paramId = self.main_window.currentAnnotation.parameters[selectedRow].id else: paramId = None param = self.paramModStack.currentWidget().saveParameter(relationship, paramId) if not param is None: param.requiredTags = self.requiredTagsListModel.getRequiredTags() param.isExperimentProperty = self.isExpProp.isChecked() selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() # Even when there is no selection, selectedRow can take a zero value. This "if" # controls for that. if len(self.paramListTblWdg.selectionModel().selectedRows()) == 0: selectedRow = -1 if selectedRow >= 0: self.main_window.currentAnnotation.parameters[selectedRow] = param else: self.main_window.currentAnnotation.parameters.append(param) self.additionMode = False nbParams = len(self.main_window.currentAnnotation.parameters) self.main_window.saveAnnotation() if selectedRow < 0 : selectedRow = nbParams-1 self.paramListTblWdg.selectRow(selectedRow) self.loadRow(selectedRow) def deleteParameter(self): selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() del self.main_window.currentAnnotation.parameters[selectedRow] self.main_window.saveAnnotation() self.refreshModelingParameters() def refreshModelingParameters(self): selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() self.loadModelingParameter(selectedRow) def loadModelingParameter(self, row = None): """ Call when a new annotation has been selected so that all the modeling parameters associated with this annotation are loaded in the parameter list. """ self.requiredTagsListModel.clear() self.requiredTagsListModel.refresh() if self.main_window.currentAnnotation is None: self.paramListModel.parameterList = [] else: self.paramListModel.parameterList = self.main_window.currentAnnotation.parameters aRowIsSelected = not row is None if aRowIsSelected: if row < 0: noRowToLoad = self.paramListTblWdg.model().rowCount()-row else: noRowToLoad = row else: ## No rows are selected noRowToLoad = -1 self.loadRow(noRowToLoad) self.newParamBtn.setEnabled(True) self.deleteParamBtn.setEnabled(aRowIsSelected) self.paramSaveAnnotBtn.setEnabled(aRowIsSelected) self.paramModStack.currentWidget().loadModelingParameter(row) self.relationWgt.loadModelingParameter(row) self.newParamsGB.setEnabled(aRowIsSelected) self.paramListModel.refresh() def loadRow(self, selectedRow = None): """ Called when a row has been selected in the table listing all the modeling parameters. It update the interface with the values associated with this specific parameter. """ def nlxCheck(id): if id in nlx2ks: return nlx2ks[id] return id def clear(): self.requiredTagsListModel.clear() self.paramModStack.currentWidget().loadRow(None) self.relationWgt.clear() self.paramListTblWdg.clearSelection() if selectedRow is None: selectedRow = self.paramListTblWdg.selectionModel().currentIndex().row() if self.main_window.currentAnnotation is None: clear() return if selectedRow < 0 or selectedRow >= len(self.main_window.currentAnnotation.parameters) : clear() return currentParameter = self.main_window.currentAnnotation.parameters[selectedRow] self.newParamBtn.setEnabled(True) self.deleteParamBtn.setEnabled(True) self.paramSaveAnnotBtn.setEnabled(True) if currentParameter.description.type == "pointValue": self.resultTypeCbo.setCurrentIndex(0) self.paramModStack.setCurrentIndex(0) elif currentParameter.description.type == "function": self.resultTypeCbo.setCurrentIndex(1) self.paramModStack.setCurrentIndex(1) elif currentParameter.description.type == "numericalTrace": self.resultTypeCbo.setCurrentIndex(2) self.paramModStack.setCurrentIndex(2) else: raise ValueError("Type of parameter description " + currentParameter.description.type + " is invalid.") self.paramModStack.currentWidget().loadRow(currentParameter) self.relationWgt.loadRow(currentParameter) self.isExpProp.setChecked(currentParameter.isExperimentProperty) ## UPDATING REQUIRED TAGS self.requiredTagsListModel.clear() for tag in currentParameter.requiredTags: self.requiredTagsListModel.addTag(tag.rootId, self.main_window.dicData[tag.rootId], tag.id, tag.name) ## Adding new required tags that may have been specified since the ## creation of this parameter instance. parameterType = getParameterTypeFromID(currentParameter.typeId) reqTags = {reqTag.rootId:reqTag for reqTag in parameterType.requiredTags} for reqTagRootId, reqTag in reqTags.items(): #print(nlxCheck(reqTagRootId), [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags]) if not nlxCheck(reqTagRootId) in [nlxCheck(tag.rootId) for tag in currentParameter.requiredTags]: self.requiredTagsListModel.addTag(reqTag.rootId, self.main_window.dicData[reqTag.rootId], reqTag.id, reqTag.name) self.requiredTagsListModel.refresh() self.newParamsGB.setEnabled(True) def selectedParameterChanged(self, selected, deselected): if len(selected.indexes()) == 0: return if self.additionMode: msgBox = QMessageBox(self) msgBox.setWindowTitle("Cancellation") msgBox.setText("Are you sure you want to cancel the addition of the new parameter being edited? If not, say no and then hit 'Save' to save this new parameter.") msgBox.setStandardButtons(QMessageBox.No | QMessageBox.Yes) msgBox.setDefaultButton(QMessageBox.No) if msgBox.exec_() == QMessageBox.Yes: self.additionMode = False self.loadRow() else: #self.paramListTblWdg.selectRow(-1) self.paramListTblWdg.clearSelection() else: self.loadRow()
def setupUi(self, Widget): # widgety rysujące kształty, instancje klasy Ksztalt self.ksztalt1 = Ksztalt(self, Ksztalty.Polygon) self.ksztalt2 = Ksztalt(self, Ksztalty.Ellipse) self.ksztaltAktywny = self.ksztalt1 # przyciski CheckBox ### uklad = QVBoxLayout() # układ pionowy self.grupaChk = QButtonGroup() for i, v in enumerate(('Kwadrat', 'Koło', 'Trójkąt', 'Linia')): self.chk = QCheckBox(v) self.grupaChk.addButton(self.chk, i) uklad.addWidget(self.chk) self.grupaChk.buttons()[self.ksztaltAktywny.ksztalt].setChecked(True) # CheckBox do wyboru aktywnego kształtu self.ksztaltChk = QCheckBox('<=') self.ksztaltChk.setChecked(True) uklad.addWidget(self.ksztaltChk) # układ poziomy dla kształtów oraz przycisków CheckBox ukladH1 = QHBoxLayout() ukladH1.addWidget(self.ksztalt1) ukladH1.addLayout(uklad) ukladH1.addWidget(self.ksztalt2) # koniec CheckBox ### # Slider i LCDNumber ### self.suwak = QSlider(Qt.Horizontal) self.suwak.setMinimum(0) self.suwak.setMaximum(255) self.lcd = QLCDNumber() self.lcd.setSegmentStyle(QLCDNumber.Flat) # układ poziomy (splitter) dla slajdera i lcd ukladH2 = QSplitter(Qt.Horizontal, self) ukladH2.addWidget(self.suwak) ukladH2.addWidget(self.lcd) ukladH2.setSizes((125, 75)) # przyciski RadioButton ### self.ukladR = QHBoxLayout() for v in ('R', 'G', 'B'): self.radio = QRadioButton(v) self.ukladR.addWidget(self.radio) self.ukladR.itemAt(0).widget().setChecked(True) # grupujemy przyciski self.grupaRBtn = QGroupBox('Opcje RGB') self.grupaRBtn.setLayout(self.ukladR) self.grupaRBtn.setObjectName('Radio') self.grupaRBtn.setCheckable(True) # układ poziomy dla grupy Radio ukladH3 = QHBoxLayout() ukladH3.addWidget(self.grupaRBtn) # koniec RadioButton ### # Lista ComboBox i SpinBox ### self.listaRGB = QComboBox(self) for v in ('R', 'G', 'B'): self.listaRGB.addItem(v) self.listaRGB.setEnabled(False) # SpinBox self.spinRGB = QSpinBox() self.spinRGB.setMinimum(0) self.spinRGB.setMaximum(255) self.spinRGB.setEnabled(False) # układ pionowy dla ComboBox i SpinBox uklad = QVBoxLayout() uklad.addWidget(self.listaRGB) uklad.addWidget(self.spinRGB) # do układu poziomego grupy Radio dodajemy układ ComboBox i SpinBox ukladH3.insertSpacing(1, 25) ukladH3.addLayout(uklad) # koniec ComboBox i SpinBox ### # przyciski PushButton ### uklad = QHBoxLayout() self.grupaP = QButtonGroup() self.grupaP.setExclusive(False) for v in ('R', 'G', 'B'): self.btn = QPushButton(v) self.btn.setCheckable(True) self.grupaP.addButton(self.btn) uklad.addWidget(self.btn) # grupujemy przyciski self.grupaPBtn = QGroupBox('Przyciski RGB') self.grupaPBtn.setLayout(uklad) self.grupaPBtn.setObjectName('Push') self.grupaPBtn.setCheckable(True) self.grupaPBtn.setChecked(False) # koniec PushButton ### # główny układ okna, wertykalny ### ukladOkna = QVBoxLayout() ukladOkna.addLayout(ukladH1) ukladOkna.addWidget(ukladH2) ukladOkna.addLayout(ukladH3) ukladOkna.addWidget(self.grupaPBtn) self.setLayout(ukladOkna) # przypisanie układu do okna głównego self.setWindowTitle('Widżety')
def __init__(self, panel): super(Widget, self).__init__(panel) layout = QVBoxLayout() self.setLayout(layout) layout.setSpacing(0) self.searchEntry = SearchLineEdit() self.treeView = QTreeView(contextMenuPolicy=Qt.CustomContextMenu) self.textView = QTextBrowser() applyButton = QToolButton(autoRaise=True) editButton = QToolButton(autoRaise=True) addButton = QToolButton(autoRaise=True) self.menuButton = QPushButton(flat=True) menu = QMenu(self.menuButton) self.menuButton.setMenu(menu) splitter = QSplitter(Qt.Vertical) top = QHBoxLayout() layout.addLayout(top) splitter.addWidget(self.treeView) splitter.addWidget(self.textView) layout.addWidget(splitter) splitter.setSizes([200, 100]) splitter.setCollapsible(0, False) top.addWidget(self.searchEntry) top.addWidget(applyButton) top.addSpacing(10) top.addWidget(addButton) top.addWidget(editButton) top.addWidget(self.menuButton) # action generator for actions added to search entry def act(slot, icon=None): a = QAction(self, triggered=slot) self.addAction(a) a.setShortcutContext(Qt.WidgetWithChildrenShortcut) icon and a.setIcon(icons.get(icon)) return a # hide if ESC pressed in lineedit a = act(self.slotEscapePressed) a.setShortcut(QKeySequence(Qt.Key_Escape)) # import action a = self.importAction = act(self.slotImport, 'document-open') menu.addAction(a) # export action a = self.exportAction = act(self.slotExport, 'document-save-as') menu.addAction(a) # apply button a = self.applyAction = act(self.slotApply, 'edit-paste') applyButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # add button a = self.addAction_ = act(self.slotAdd, 'list-add') a.setShortcut(QKeySequence(Qt.Key_Insert)) addButton.setDefaultAction(a) menu.addSeparator() menu.addAction(a) # edit button a = self.editAction = act(self.slotEdit, 'document-edit') a.setShortcut(QKeySequence(Qt.Key_F2)) editButton.setDefaultAction(a) menu.addAction(a) # set shortcut action a = self.shortcutAction = act(self.slotShortcut, 'preferences-desktop-keyboard-shortcuts') menu.addAction(a) # delete action a = self.deleteAction = act(self.slotDelete, 'list-remove') a.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Delete)) menu.addAction(a) # restore action a = self.restoreAction = act(self.slotRestore) menu.addSeparator() menu.addAction(a) # help button a = self.helpAction = act(self.slotHelp, 'help-contents') menu.addSeparator() menu.addAction(a) self.treeView.setSelectionBehavior(QTreeView.SelectRows) self.treeView.setSelectionMode(QTreeView.ExtendedSelection) self.treeView.setRootIsDecorated(False) self.treeView.setAllColumnsShowFocus(True) self.treeView.setModel(model.model()) self.treeView.setCurrentIndex(QModelIndex()) # signals self.searchEntry.returnPressed.connect(self.slotReturnPressed) self.searchEntry.textChanged.connect(self.updateFilter) self.treeView.doubleClicked.connect(self.slotDoubleClicked) self.treeView.customContextMenuRequested.connect(self.showContextMenu) self.treeView.selectionModel().currentChanged.connect(self.updateText) self.treeView.model().dataChanged.connect(self.updateFilter) # highlight text self.highlighter = highlight.Highlighter(self.textView.document()) # complete on snippet variables self.searchEntry.setCompleter(QCompleter([ ':icon', ':indent', ':menu', ':name', ':python', ':selection', ':set', ':symbol', ':template', ':template-run'], self.searchEntry)) self.readSettings() app.settingsChanged.connect(self.readSettings) app.translateUI(self) self.updateColumnSizes() self.setAcceptDrops(True)