class ListView(View): base = True def show(self): super(ListView, self).show() win = self.binder._parent minimum = self.get_minimal_size() height = win.height() if win.height() > minimum[0] else minimum[0] width = win.width() if win.width() > minimum[1] else minimum[1] win.resize(width, height) def create_design(self): header = self.get_header_labels() self.lay = QVBoxLayout(self) self.list = QTableWidget(0, len(header), self) self.list.setSelectionBehavior(QAbstractItemView.SelectRows) self.list.setHorizontalHeaderLabels(header) self.list.doubleClicked.connect(self.on_doubleClicked) self.lay.addWidget(self.list) def append_row(self, cols, element_id=None): rowCount = self.list.rowCount() self.list.insertRow(rowCount) for index, value in enumerate(cols): col = QTableWidgetItem(value) col.element_id = element_id col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.list.setItem(rowCount, index, col) def on_doubleClicked(self, index): item = self.list.item(index.row(), index.column()) self.binder._parent.open('edit', item.element_id) def clear_list(self): while self.list.rowCount(): self.list.removeRow(0) def generate_signals(self): super(ListView, self).generate_signals() self.add_signal(self.fill) def fill(self, elements): self.clear_list() for element in elements: cols = self.get_row_from_obj(element) self.append_row(cols, self.get_element_id(element)) def get_element_id(self, element): return element.id
class ui(QWidget): def __init__(self): QWidget.__init__(self) self.setupUI() self.id = 1 self.lines = [] self.editable = True self.des_sort = True self.faker = Factory.create() self.btn_add.clicked.connect(self.add_line) self.btn_del.clicked.connect(self.del_line) self.btn_modify.clicked.connect(self.modify_line) self.btn_select_line.clicked.connect(self.select_line) self.btn_select_single.clicked.connect(self.deny_muti_line) self.btn_sort.clicked.connect(self.sortItem) self.btn_set_header.clicked.connect(self.setheader) self.btn_set_middle.clicked.connect(self.middle) self.table.cellChanged.connect(self.cellchange) self.btn_noframe.clicked.connect(self.noframe) # # Sess = sessionmaker(bind = engine) def setupUI(self): self.setWindowTitle(windowTital) self.resize(640, 480) self.table = QTableWidget(self) self.btn_add = QPushButton(u'增加') self.btn_del = QPushButton(u'删除') self.btn_modify = QPushButton(u'可以编辑') self.btn_select_line = QPushButton(u'选择整行') self.btn_select_single = QPushButton(u'禁止选多行') self.btn_sort = QPushButton(u'以分数排序') self.btn_set_header = QPushButton(u'标头设置') self.btn_set_middle = QPushButton(u'文字居中加颜色') self.btn_noframe = QPushButton(u'取消边框颜色交替') self.spacerItem = QSpacerItem(20, 20, QSizePolicy.Minimum, QSizePolicy.Expanding) self.vbox = QVBoxLayout() self.vbox.addWidget(self.btn_add) self.vbox.addWidget(self.btn_del) self.vbox.addWidget(self.btn_modify) self.vbox.addWidget(self.btn_select_line) self.vbox.addWidget(self.btn_select_single) self.vbox.addWidget(self.btn_sort) self.vbox.addWidget(self.btn_set_header) self.vbox.addWidget(self.btn_set_middle) self.vbox.addWidget(self.btn_noframe) self.vbox.addSpacerItem( self.spacerItem) #可以用addItem也可以用addSpacerItem方法添加,没看出哪里不一样 self.txt = QLabel() self.txt.setMinimumHeight(50) self.vbox2 = QVBoxLayout() self.vbox2.addWidget(self.table) self.vbox2.addWidget(self.txt) self.hbox = QHBoxLayout() self.hbox.addLayout(self.vbox2) self.hbox.addLayout(self.vbox) self.setLayout(self.hbox) self.table.setColumnCount(4) ##设置列数 self.headers = [u'id', u'选择', u'姓名', u'成绩', u'住址'] self.table.setHorizontalHeaderLabels(self.headers) self.show() def add_line(self): self.table.cellChanged.disconnect() row = self.table.rowCount() self.table.setRowCount(row + 1) id = str(self.id) ck = QCheckBox() h = QHBoxLayout() h.setAlignment(Qt.AlignCenter) h.addWidget(ck) w = QWidget() w.setLayout(h) name = self.faker.name() score = str(random.randint(50, 99)) add = self.faker.address() self.table.setItem(row, 0, QTableWidgetItem(id)) self.table.setCellWidget(row, 1, w) self.table.setItem(row, 2, QTableWidgetItem(name)) self.table.setItem(row, 3, QTableWidgetItem(score)) self.table.setItem(row, 4, QTableWidgetItem(add)) self.id += 1 self.lines.append([id, ck, name, score, add]) self.settext(u'自动生成随机一行数据!,checkbox设置为居中显示') self.table.cellChanged.connect(self.cellchange) def del_line(self): removeline = [] for line in self.lines: if line[1].isChecked(): row = self.table.rowCount() for x in range(row, 0, -1): if line[0] == self.table.item(x - 1, 0).text(): self.table.removeRow(x - 1) removeline.append(line) for line in removeline: self.lines.remove(line) self.settext(u'删除在左边checkbox中选中的行,使用了一个笨办法取得行号\n,不知道有没有其他可以直接取得行号的方法!') def modify_line(self): if self.editable == True: self.table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.btn_modify.setText(u'禁止编辑') self.editable = False else: self.table.setEditTriggers(QAbstractItemView.AllEditTriggers) self.btn_modify.setText(u'可以编辑') self.editable = True self.settext(u'设置,是否可以编辑整个表格') def select_line(self): if self.table.selectionBehavior() == 0: self.table.setSelectionBehavior(1) self.btn_select_line.setStyleSheet('background-color:lightblue') else: self.table.setSelectionBehavior(0) self.btn_select_line.setStyleSheet('') self.settext(u'默认时,点击单元格,只可选择一个格,此处设置为可选择整行') def deny_muti_line(self): if self.table.selectionMode() in [2, 3]: self.table.setSelectionMode(QAbstractItemView.SingleSelection) self.btn_select_single.setStyleSheet('background-color:lightblue') else: self.table.setSelectionMode(QAbstractItemView.ExtendedSelection) self.btn_select_single.setStyleSheet('') self.settext(u'点击时会轮换以多行或单行选择,默认是可以同时选择多行') def sortItem(self): if self.des_sort == True: self.table.sortItems(3, Qt.DescendingOrder) self.des_sort = False self.btn_sort.setStyleSheet('background-color:lightblue') self.table.setSortingEnabled(True) # 设置表头可以自动排序 else: self.table.sortItems(3, Qt.AscendingOrder) self.des_sort = True self.btn_sort.setStyleSheet('background-color:lightblue') self.table.setSortingEnabled(False) self.settext(u'点击时会轮换以升序降序排列,但排序时,会使自动列宽失效!') def setheader(self): font = QFont(u'微软雅黑', 12) font.setBold(True) self.table.horizontalHeader().setFont(font) # 设置表头字体 self.table.setColumnWidth(0, 50) self.table.setColumnWidth(1, 50) self.table.setColumnWidth(3, 100) self.table.horizontalHeader().setSectionResizeMode( 2, QHeaderView.Stretch) self.table.horizontalHeader().setStyleSheet( 'QHeaderView::section{background:gray}') self.table.horizontalHeader().setFixedHeight(50) self.table.setColumnHidden(0, True) self.btn_set_header.setStyleSheet('background-color:lightblue') self.settext( u'设置标头字体及字号,隐藏ID列,设置标头除姓名外全部为固定宽度\n,设置姓名列自动扩展宽度,设置标头行高,设置标头背景色') def middle(self): self.btn_set_middle.setStyleSheet('background-color:lightblue') self.table.setStyleSheet('color:green;') row = self.table.rowCount() for x in range(row): for y in range(4): if y != 1: item = self.table.item(x, y) item.setTextAlignment(Qt.AlignCenter) else: pass self.btn_set_middle.setStyleSheet('background-color:lightblue') self.settext(u'将文字居中显示,设置文字颜色') def cellchange(self, row, col): item = self.table.item(row, col) txt = item.text() self.settext(u'第%s行,第%s列 , 数据改变为:%s' % (row, col, txt)) def noframe(self): self.table.setAlternatingRowColors(True) self.table.setFrameStyle(QFrame.NoFrame) self.table.setStyleSheet('color:green;' 'gridline-color:white;' 'border:0px solid gray') self.settext(u'取消表的框线,\n 取消表格内框') def settext(self, txt): font = QFont(u'微软雅黑', 10) self.txt.setFont(font) self.txt.setText(txt)
class CustomWidget(QtGui.QMainWindow): def __init__(self): """ Constructor """ QtGui.QMainWindow.__init__(self) self.name = "Custom widget" self.central_widget = QtGui.QWidget() self.setCentralWidget(self.central_widget) # TODO: This is ugly, improve it self.iconp = JConfig().icons_path self._createLayout() def _createGui(self): """ Subclasses must override this depending on the elements they want to add self._createOutputTree(), self._createOutputTable(), self._createOutputWindow() and add them to the corresponding layouts. """ raise NotImplementedError def _createToolBar(self, name): """ Subclasses need to define the specific Actions """ self.toolbar = self.addToolBar(name) self.toolbar.setMovable(False) def _createLayout(self): """ This creates the basic layout: Buttons & Outputs """ # Layouts (This is a common disposition) main_layout = QtGui.QVBoxLayout() self.button_layout = QtGui.QHBoxLayout() output_layout = QtGui.QVBoxLayout() # You will need to create your buttons # and add them to your layout like this: # self.button_layout.addWidget(button_1) # Output Layout Inner (QSplitter) # Add as many widgets as you please # They will be ordered vertically and # be resizable by the user # self.splitter.addWidget(self.table_label) # self.splitter.addWidget(...) self.splitter = QSplitter(QtCore.Qt.Vertical) # Nested layouts main_layout.addLayout(self.button_layout) output_layout.addWidget(self.splitter) main_layout.addLayout(output_layout) self.central_widget.setLayout(main_layout) def _createOutputWindow(self): """ Some binary analysis commands will output to this. """ self.output_label = QtGui.QLabel('Output') self.output_window = QTextEdit() self.output_window.setFontPointSize(10) self.output_window.setReadOnly(True) # Save it for later use self.output_window.original_textcolor = self.output_window.textColor() def _createOutputTable(self): """ A vanilla QTableWidget. Callbacks modify its properties, like number of columns, etc. """ self.table_label = QtGui.QLabel('Table Output') self.table = QTableWidget() self.table.setColumnCount(3) self.table.setColumnWidth(0, 100) self.table.setColumnWidth(1, 300) self.table.setColumnWidth(2, 300) self.table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) # Connect signals to slots self.table.customContextMenuRequested.connect(self._tablePopup) self.table.horizontalHeader().sectionDoubleClicked.connect( self._tableHeaderDoubleClicked) self.table.cellDoubleClicked.connect(self._tableCellDoubleClicked) def _createOutputTree(self): """ A QtreeWidget. Initially used to display those pesky dword comparison to immediate values. """ self.tree_label = QtGui.QLabel('Tree Output') self.tree = QTreeWidget() self.tree.setColumnCount(3) self.tree.setColumnWidth(0, 150) self.tree.setColumnWidth(1, 150) self.tree.setColumnWidth(2, 50) # Connect signals to slots self.tree.itemDoubleClicked.connect(self._treeElementDoubleClicked) ################################################################# # GUI Callbacks ################################################################# def _console_output(self, s="", err=False): """ Convenience wrapper """ if err: # Error message err_color = QColor('red') self.output_window.setTextColor(err_color) self.output_window.append(s) # restore original color self.output_window.setTextColor( self.output_window.original_textcolor) else: self.output_window.append(s) def _tableCellDoubleClicked(self, row, col): """ Most of the info displayed in QTableWidgets represent addresses. Default action: try to jump to it. """ it = self.table.item(row, col).text() try: addr = int(it, 16) jump_to_address(addr) except ValueError: self._console_output("[!] That does not look like an address...", err=True) return def _tablePopup(self, pos): """ Popup menu activated clicking the secondary button on the table """ menu = QtGui.QMenu() # Add menu entries delRow = menu.addAction(QIcon(self.iconp + "close.png"), "Delete Row") selItem = menu.addAction(QIcon(self.iconp + "bookmark.png"), "Mark entry") menu.addSeparator() origFunc = menu.addAction(QIcon(self.iconp + "lightning.png"), "Select origin function") destFunc = menu.addAction(QIcon(self.iconp + "flag.png"), "Select destination function") # Get entry clicked action = menu.exec_(self.mapToGlobal(pos)) # Dispatch :) if action == delRow: self.table.removeRow(self.table.currentRow()) elif action == selItem: self.table.currentItem().setBackground(QtGui.QColor('red')) elif action == origFunc: try: addr = self.table.currentItem().text() InfoUI.function_orig_ea = int(addr, 16) except: self._console_output("This does not look like an address...", err=True) elif action == destFunc: try: addr = self.table.currentItem().text() InfoUI.function_dest_ea = int(addr, 16) except: self._console_output("This does not look like an address...", err=True) def _tableHeaderDoubleClicked(self, index): """ Used to sort the contents """ self.table.sortItems(index, order=QtCore.Qt.AscendingOrder) def _treeElementDoubleClicked(self, item, column): """ QTreeWidgetElement callback. Basically it jumps to the selected address in IDA disassembly window. """ try: # Only interested in addresses addr_int = int(item.text(column), 16) jump_to_address(addr_int) # Paint some color item.setBackground(column, QtGui.QColor('green')) except: self._console_output("[!] That does not look like an address...", err=True)
class FoamDictWidget(QWidget): "QWidget to view and edit simple Foam Dictionary" def __init__(self, variable_setting, parent=None): super(FoamDictWidget, self).__init__(parent) self.buttonLayout = QHBoxLayout() self.pushButtonInsert = QPushButton("Add new row") self.pushButtonRemove = QPushButton("Del selected row") self.pushButtonRestore = QPushButton("Restore table") self.pushButtonClear = QPushButton("Clear table") self.buttonLayout.addWidget(self.pushButtonInsert) self.buttonLayout.addWidget(self.pushButtonRemove) self.buttonLayout.addWidget(self.pushButtonRestore) self.buttonLayout.addWidget(self.pushButtonClear) self.tableWidget = QTableWidget() # header, should not sort, has vertical scrollbar # set column count, fixed to 2, size of TableItem self.tableWidget.setColumnCount(2) # self.tableWidget.setHorizontalHeaderItem(0, ) self.tableWidget.setHorizontalHeaderLabels(['key', 'value text']) # set a default row count, insert as needed self.tableWidget.setRowCount(0) self.buttonPreview = QPushButton('Preview FoamFile write-out') # self.buttonLoad = QPushButton('load dict from existing case ') self.buttonCustomize = QPushButton('Customize (convert into raw)') self.textPreview = QTextEdit('') self.textPreview.setVisible(False) self.textPreview.setEnabled(False) #PySide has different name other than @QtCore.pyqtSlot, but PySide.QtCore.SLOT #PySide has different name other than @QtCore.pyqtSlot, but PySide.QtCore.SLOT self.pushButtonInsert.clicked.connect(self.insertRow) self.pushButtonRemove.clicked.connect(self.removeRow) self.pushButtonRestore.clicked.connect(self.restoreDict) self.pushButtonClear.clicked.connect(self.clearDict) # self.tableWidget.doubleClicked.connect( self.showPreview) # does not work for PySide self.buttonPreview.clicked.connect(self.showPreview) self.buttonCustomize.clicked.connect(self.customizeDict) self._previewing = False self.settings = variable_setting self.previous_settings = self.settings #self.restoreDict() self.updateDictView(self.settings) self.myLayout = QVBoxLayout() self.myLayout.addLayout(self.buttonLayout) self.myLayout.addWidget(self.tableWidget) self.myLayout.addWidget(self.buttonPreview) self.myLayout.addWidget(self.textPreview) self.setLayout(self.myLayout) def dict(self): _settings = OrderedDict() for i in range(self.tableWidget.rowCount()): k = self.tableWidget.item(i, 0).text() v = self.tableWidget.item( i, 1).text() # data() will return QVariant type-> python type # validated by non-empty string if k and v: _settings[k] = v return _settings def setDict(self, settings): # self.settings = settings self.updateDictView(self.settings) def restoreDict(self): self.settings = self.previous_settings self.updateDictView(self.settings) def updateDictView(self, variable_settings): i = 0 self.clearDict() # will clear contents, but leave row text empty N = self.tableWidget.rowCount() for k, v in variable_settings.items(): # translate seq into unicode if i >= N: self.tableWidget.insertRow(i) kitem = QTableWidgetItem(k) # also set flags and state, type vitem = QTableWidgetItem( v) # automaticall convert str to unicode to feed QWidget? self.tableWidget.setItem(i, 0, kitem) self.tableWidget.setItem( i, 1, vitem) # currently only works for string value ! i += 1 #@pyqtSlot() # PySide use another name "QtCore.Slot()" def insertRow(self): nRows = self.tableWidget.rowCount() self.tableWidget.insertRow(nRows) # inset one row at the end kitem = QTableWidgetItem("") # also set flags and state, type vitem = QTableWidgetItem("") self.tableWidget.setItem(nRows, 0, kitem) self.tableWidget.setItem(nRows, 1, vitem) def removeRow( self, rowID=None): # : Optional[int] typing is not supported by python2 if rowID == None: for ind in self.tableWidget.selectedIndexes(): self.tableWidget.removeRow(ind.row()) else: nRows = self.tableWidget.rowCount() if rowID < nRows: self.tableWidget.removeRow(rowID) def clearDict(self): self.tableWidget.clearContents() # keep the header, clear all items if self._previewing: self.showPreview() def customizeDict(self): # pass def loadDefault(self): # generated by FoamBaseBuilder.BasicBuilder #TODO: load the generated from FoamCaseBuilder pass def showPreview(self): if self._previewing: self._previewing = False self.textPreview.setVisible(False) self.buttonPreview.setText('click to preview write out') else: self._previewing = True self.buttonPreview.setText('click on text to hide preview') # enable scrollbar ? self.textPreview.setText(self.printDict()) self.textPreview.setVisible(True) def printDict(self): dictText = "{\n" for k, v in self.dict().items(): dictText += " {} {};\n".format(str(k), str(v)) dictText += "}" return dictText
class CustomWidget(QtGui.QMainWindow): def __init__(self): """ Constructor """ QtGui.QMainWindow.__init__(self) self.name = "Custom widget" self.central_widget = QtGui.QWidget() self.setCentralWidget(self.central_widget) # TODO: This is ugly, improve it self.iconp = JConfig().icons_path self._createLayout() def _createGui(self): """ Subclasses must override this depending on the elements they want to add self._createOutputTree(), self._createOutputTable(), self._createOutputWindow() and add them to the corresponding layouts. """ raise NotImplementedError def _createToolBar(self, name): """ Subclasses need to define the specific Actions """ self.toolbar = self.addToolBar(name) self.toolbar.setMovable(False) def _createLayout(self): """ This creates the basic layout: Buttons & Outputs """ # Layouts (This is a common disposition) main_layout = QtGui.QVBoxLayout() self.button_layout = QtGui.QHBoxLayout() output_layout = QtGui.QVBoxLayout() # You will need to create your buttons # and add them to your layout like this: # self.button_layout.addWidget(button_1) # Output Layout Inner (QSplitter) # Add as many widgets as you please # They will be ordered vertically and # be resizable by the user # self.splitter.addWidget(self.table_label) # self.splitter.addWidget(...) self.splitter = QSplitter(QtCore.Qt.Vertical) # Nested layouts main_layout.addLayout(self.button_layout) output_layout.addWidget(self.splitter) main_layout.addLayout(output_layout) self.central_widget.setLayout(main_layout) def _createOutputWindow(self): """ Some binary analysis commands will output to this. """ self.output_label = QtGui.QLabel('Output') self.output_window = QTextEdit() self.output_window.setFontPointSize(10) self.output_window.setReadOnly(True) # Save it for later use self.output_window.original_textcolor = self.output_window.textColor() def _createOutputTable(self): """ A vanilla QTableWidget. Callbacks modify its properties, like number of columns, etc. """ self.table_label = QtGui.QLabel('Table Output') self.table = QTableWidget() self.table.setColumnCount(3) self.table.setColumnWidth(0, 100) self.table.setColumnWidth(1, 300) self.table.setColumnWidth(2, 300) self.table.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) # Connect signals to slots self.table.customContextMenuRequested.connect(self._tablePopup) self.table.horizontalHeader().sectionDoubleClicked.connect(self._tableHeaderDoubleClicked) self.table.cellDoubleClicked.connect(self._tableCellDoubleClicked) def _createOutputTree(self): """ A QtreeWidget. Initially used to display those pesky dword comparison to immediate values. """ self.tree_label = QtGui.QLabel('Tree Output') self.tree = QTreeWidget() self.tree.setColumnCount(3) self.tree.setColumnWidth(0, 150) self.tree.setColumnWidth(1, 150) self.tree.setColumnWidth(2, 50) # Connect signals to slots self.tree.itemDoubleClicked.connect(self._treeElementDoubleClicked) ################################################################# # GUI Callbacks ################################################################# def _console_output(self, s = "", err = False): """ Convenience wrapper """ if err: # Error message err_color = QColor('red') self.output_window.setTextColor(err_color) self.output_window.append(s) # restore original color self.output_window.setTextColor(self.output_window.original_textcolor) else: self.output_window.append(s) def _tableCellDoubleClicked(self, row, col): """ Most of the info displayed in QTableWidgets represent addresses. Default action: try to jump to it. """ it = self.table.item(row, col).text() try: addr = int(it, 16) jump_to_address(addr) except ValueError: self._console_output("[!] That does not look like an address...", err = True) return def _tablePopup(self, pos): """ Popup menu activated clicking the secondary button on the table """ menu = QtGui.QMenu() # Add menu entries delRow = menu.addAction(QIcon(self.iconp + "close.png"), "Delete Row") selItem = menu.addAction(QIcon(self.iconp + "bookmark.png"), "Mark entry") menu.addSeparator() origFunc = menu.addAction(QIcon(self.iconp + "lightning.png"), "Select origin function") destFunc = menu.addAction(QIcon(self.iconp + "flag.png"), "Select destination function") # Get entry clicked action = menu.exec_(self.mapToGlobal(pos)) # Dispatch :) if action == delRow: self.table.removeRow(self.table.currentRow()) elif action == selItem: self.table.currentItem().setBackground(QtGui.QColor('red')) elif action == origFunc: try: addr = self.table.currentItem().text() InfoUI.function_orig_ea = int(addr, 16) except: self._console_output("This does not look like an address...", err = True) elif action == destFunc: try: addr = self.table.currentItem().text() InfoUI.function_dest_ea = int(addr, 16) except: self._console_output("This does not look like an address...", err = True) def _tableHeaderDoubleClicked(self, index): """ Used to sort the contents """ self.table.sortItems(index, order = QtCore.Qt.AscendingOrder) def _treeElementDoubleClicked(self, item, column): """ QTreeWidgetElement callback. Basically it jumps to the selected address in IDA disassembly window. """ try: # Only interested in addresses addr_int = int(item.text(column), 16) jump_to_address(addr_int) # Paint some color item.setBackground(column, QtGui.QColor('green')) except: self._console_output("[!] That does not look like an address...", err = True)