class PangoFileWidget(PangoDockWidget): def __init__(self, title, parent=None): super().__init__(title, parent) self.setFixedWidth(160) self.file_model = QFileSystemModel() self.file_model.setFilter(QDir.Files | QDir.NoDotAndDotDot) self.file_model.setNameFilters(["*.jpg", "*.png"]) self.file_model.setNameFilterDisables(False) self.th_provider = ThumbnailProvider() self.file_model.setIconProvider(self.th_provider) self.file_view = QListView() self.file_view.setModel(self.file_model) self.file_view.setViewMode(QListView.IconMode) self.file_view.setFlow(QListView.LeftToRight) self.file_view.setIconSize(QSize(150, 150)) self.setWidget(self.file_view) def select_next_image(self): c_idx = self.file_view.currentIndex() idx = c_idx.siblingAtRow(c_idx.row()+1) if idx.row() != -1: self.file_view.setCurrentIndex(idx) def select_prev_image(self): c_idx = self.file_view.currentIndex() idx = c_idx.siblingAtRow(c_idx.row()-1) if idx.row() != -1: self.file_view.setCurrentIndex(idx)
class TeamChooserWidget(QWidget): def __init__(self, parent, on_next, league=None): super().__init__(parent) self.layout = QVBoxLayout() self.list_view = QListView() self.league = league self.model = TeamListModel(league) self.list_view.setModel(self.model) self.list_view.setSelectionMode(QAbstractItemView.MultiSelection) self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.list_view.customContextMenuRequested.connect(self.list_context_menu) self.layout.addWidget(self.list_view) self.team_add = AddItemWidget(self, "New Team Name: ", self.add_team, unavailable_options=self.model.all_team_names) self.layout.addWidget(self.team_add) self.button_h_layout = QHBoxLayout() self.button_cancel = QPushButton("Cancel") self.button_cancel.clicked.connect(self.on_cancel) self.button_next = QPushButton("Next") self.button_next.clicked.connect(on_next) self.button_h_layout.addWidget(self.button_cancel) self.button_h_layout.addWidget(self.button_next) self.layout.addLayout(self.button_h_layout) self.setLayout(self.layout) self.new_teams = [] def add_team(self, name): self.new_teams.append(name) team = Team.create(name=name) self.model.add_team(team) def list_context_menu(self, pos): self.listMenu = QMenu() current_index = self.list_view.currentIndex() select = self.listMenu.addAction("Select") select.triggered.connect( lambda: self.list_view.selectionModel().select(current_index, QtCore.QItemSelectionModel.Select) ) deselect = self.listMenu.addAction("Deselect") deselect.triggered.connect( lambda: self.list_view.selectionModel().select(current_index, QtCore.QItemSelectionModel.Deselect) ) delete = self.listMenu.addAction("Delete") delete.setDisabled(current_index.data() not in self.new_teams) delete.triggered.connect(lambda: self.model.delete_team(current_index.row())) parentPosition = self.list_view.mapToGlobal(QtCore.QPoint(0, 0)) self.listMenu.move(parentPosition + pos) self.listMenu.show() def on_cancel(self): self.model.delete_added_teams() self.window().close() def get_selected_teams(self): teams = [] for i in self.list_view.selectedIndexes(): teams.append(self.model.get_team(i.row())) return teams
class TBox(QWidget): def __init__(self): super().__init__() exitShortcut = QShortcut(QKeySequence('Ctrl+W'), self, qApp.quit) self.connect = Connect() self.all_models = self.connect.session.query(Models).all() self.labelkey_name = QLabel('Name', self) self.labelkey_parts = QLabel('Parts', self) self.labelkey_current_quantity = QLabel('Current Quantity', self) self.labelval_name = QLabel('Name', self) self.labelval_parts = QLabel('Parts', self) self.labelval_current_quantity = QLabel('Current Quantity', self) self.showInfo('M1') self.list = QListView(self) self.list_model = QStandardItemModel(self.list) self.createList() print('Current index of view: ', self.list.currentIndex()) self.hboxlayout = QHBoxLayout() self.label_grid = QGridLayout() self.buildLayout() self.show() def showInfo(self, queryitem): query = self.connect.session.query(Models).filter_by( name=queryitem).one() self.labelval_name.setText(query.name) self.labelval_parts.setText(query.parts) self.labelval_current_quantity.setText(str(query.current_quantity)) def createList(self): for model in self.all_models: item = QStandardItem(model.name) self.list_model.appendRow(item) self.list.setModel(self.list_model) self.list.setMinimumSize(150, 200) self.list.setMaximumSize(150, 600) self.list.show() def buildLayout(self): self.label_grid.addWidget(self.labelkey_name, 0, 0) self.label_grid.addWidget(self.labelkey_parts, 1, 0) self.label_grid.addWidget(self.labelkey_current_quantity, 2, 0) self.label_grid.addWidget(self.labelval_name, 0, 1) self.label_grid.addWidget(self.labelval_parts, 1, 1) self.label_grid.addWidget(self.labelval_current_quantity, 2, 1) self.hboxlayout.addWidget(self.list) self.hboxlayout.addLayout(self.label_grid) self.setLayout(self.hboxlayout)
class NameList(QDockWidget): def __init__(self, window): super(NameList, self).__init__('Current Plots') self.namelist_model = QStandardItemModel() self.namelist_view = QListView() self.namelist_view.setModel(self.namelist_model) self.setWidget(self.namelist_view) self.window = window self.plot_dict = {} self.namelist_view.doubleClicked.connect(self.activate_item) self.namelist_view.setContextMenuPolicy(QtConst.ActionsContextMenu) delete_action = QAction("Delete Selected", self.namelist_view) ### pause_action = QAction("Stop Script", self.namelist_view) delete_action.triggered.connect(self.delete_item) pause_action.triggered.connect(self.pause) self.namelist_view.addAction(delete_action) ### self.namelist_view.addAction(pause_action) def activate_item(self, index): item = self.namelist_model.itemFromIndex(index) plot = self.plot_dict[str(item.text())] if plot.closed: plot.closed = False self.window.add_plot(plot) def delete_item(self): index = self.namelist_view.currentIndex() item = self.namelist_model.itemFromIndex(index) del self[str(item.text())] def pause(self): sock = socket.socket() sock.connect(('localhost', 9091)) sock.send(b'stop') sock.close() def __getitem__(self, item): return self.plot_dict[item] def __setitem__(self, name, plot): model = QStandardItem(name) model.setEditable(False) self.namelist_model.appendRow(model) self.plot_dict[name] = plot def __contains__(self, value): return value in self.plot_dict def __delitem__(self, name): self.namelist_model.removeRow(self.namelist_model.findItems(name)[0].index().row()) self.plot_dict[name].close() del self.plot_dict[name] def keys(self): return list(self.plot_dict.keys());
class Demo(QWidget): def __init__(self): super(Demo, self).__init__() self.item_list = ['item %s' % i for i in range(11)] # 1 self.model_1 = QStringListModel(self) self.model_1.setStringList(self.item_list) self.model_2 = QStringListModel(self) # 2 self.listview_1 = QListView(self) # 3 self.listview_1.setModel(self.model_1) self.listview_1.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listview_1.doubleClicked.connect( lambda: self.change_func(self.listview_1)) self.listview_2 = QListView(self) # 4 self.listview_2.setModel(self.model_2) self.listview_2.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listview_2.doubleClicked.connect( lambda: self.change_func(self.listview_2)) self.pic_label = QLabel(self) # 5 self.pic_label.setPixmap(QPixmap('arrow.png')) self.h_layout = QHBoxLayout() self.h_layout.addWidget(self.listview_1) self.h_layout.addWidget(self.pic_label) self.h_layout.addWidget(self.listview_2) self.setLayout(self.h_layout) def change_func(self, listview): if listview == self.listview_1: # 6 self.model_2.insertRows(self.model_2.rowCount(), 1) data = self.listview_1.currentIndex().data() index = self.model_2.index(self.model_2.rowCount() - 1) self.model_2.setData(index, data) else: # 7 self.model_2.removeRows(self.listview_2.currentIndex().row(), 1)
class SettingWindow(QWidget): # on_addButtonClicked=pyqtSignal() # on_removeButtonClicked=pyqtSignal() # on_okButtonClicked=pyqtSignal() finished=pyqtSignal() def __init__(self): QWidget.__init__(self) self.listview=QListView(self) self.addButton=QPushButton(self) self.removeButton=QPushButton(self) self.resize(630,440) self.okButton=QPushButton(self) self.listview.setGeometry(30,30,410,351) self.addButton.setGeometry(490,40,80,22) self.addButton.setText("add") self.addButton.clicked.connect(self.click_add) self.removeButton.setGeometry(490,80,80,22) self.removeButton.setText("remove") self.removeButton.clicked.connect(self.click_remove) self.okButton.setGeometry(490,150,80,22) self.okButton.setText("ok") self.okButton.clicked.connect(self.click_ok) # self.aw=null self.fresh() def click_ok(self): self.finished.emit() self.close() def click_add(self): self.aw=AddWindow() self.aw.show() self.aw.okSig.connect(self.fresh) def click_remove(self): self.remove() def fresh(self): confFile=open("conf","r") self.listModel=QStandardItemModel() self.itemList=cPickle.load(confFile) confFile.close() for item in self.itemList: itemView=QStandardItem(QIcon(item.path),item.name) itemView.setEditable(False) self.listModel.appendRow(itemView) self.listview.setModel(self.listModel) def remove(self): index=self.listview.currentIndex().row() self.itemList.pop(index) self.listModel.removeRow(index) confFile=open("conf","w") cPickle.dump(self.itemList,confFile) confFile.close()
class HardwareSelector(QDialog): def __init__(self, host, port, parent=None): QDialog.__init__(self, parent) self.host = host self.port = port self._layout = QVBoxLayout(self) self.setWindowTitle("Hardware on " + self.host + ":" + str(self.port)) self.setMinimumSize(800, 600) self.hardware = None self.selectedHW = None self._model = None self._lbl_status = QLabel() self._layout.addWidget(self._lbl_status) self._layoutH = QHBoxLayout() self._layout.addLayout(self._layoutH) self._hwlist = QListView() self._layoutH.addWidget(self._hwlist) self._lbl_hw = QLabel() self._lbl_hw.setMinimumWidth(400) self._lbl_hw.setMargin(10) self._lbl_hw.setFont(QFontDatabase.systemFont(QFontDatabase.FixedFont)) #self._layoutH.addWidget(self._hwlabel) self._hwscroll = QScrollArea() self._hwscroll.setWidget(self._lbl_hw) self._layoutH.addWidget(self._hwscroll) self._layoutB = QHBoxLayout() self._layout.addLayout(self._layoutB) self._btn_select = QPushButton("Select") self._layoutB.addWidget(self._btn_select) self._btn_rescan = QPushButton("Rescan") self._layoutB.addWidget(self._btn_rescan) self._btn_cancel = QPushButton("Cancel") self._layoutB.addWidget(self._btn_cancel) self._btn_select.clicked.connect(self._select) self._btn_cancel.clicked.connect(lambda: (self._quitScan(), self.close())) self._btn_rescan.clicked.connect(self._prepareScan) self._disable() self._start() def _start(self, ret=None): if not ret: self._prepareScan() ret = self._getHardware() if ret: self.hardware = ret[0] if len(self.hardware) == 0: self._lbl_status.setText( "No Hardware detected. Is Caffepath set?") elif ret[1] == 0: self._lbl_status.setText("Currently selected CPU: " + ret[0][0]["name"]) else: self._lbl_status.setText("Currently selected GPU " + str(ret[1]) + ": " + ret[0][ret[1]]["name"]) self._model = self.HardwareListModel(self.hardware) self._hwlist.setModel(self._model) self._hwlist.selectionModel().currentChanged.connect( self._onSelection) self._enable() def _enable(self): self._hwlist.setEnabled(True) self._btn_rescan.setEnabled(True) def _disable(self): self._hwlist.setEnabled(False) self._btn_select.setEnabled(False) self._btn_rescan.setEnabled(False) self._lbl_hw.setText("") if self._hwlist.selectionModel(): self._hwlist.selectionModel().currentChanged.disconnect() self._hwlist.setModel(None) def _select(self): self.selectedHW = self._hwlist.currentIndex().row() self.close() def _onSelection(self): row = self._hwlist.currentIndex().row() if row != -1: self._lbl_hw.setText(self._getText(row)) self._lbl_hw.adjustSize() self._btn_select.setEnabled(True) else: self._lbl_hw.setText("") def _getText(self, row): log = self.hardware[row]["log"] text = "" for l in log: text += l + "\n" return text def _prepareScan(self): self._disable() ct = buildTransaction(self.host, self.port) if ct: self.ct = ct msg = {"key": Protocol.SCANHARDWARE} self.ct.send(msg) self.ct.bufferReady.connect(self._processScan) self.ct.socketClosed.connect(self._socketClosed) self._lbl_status.setText("Start scanning...") else: self._lbl_status.setText("Failed to start Scan.") def _processScan(self): msg = self.ct.asyncRead() if msg["status"]: if "finished" in msg.keys(): if msg["finished"]: self._quitScan() self._lbl_status.setText("Scan finished.") self._start([msg["hardware"], msg["current"]]) else: if "id" in msg.keys(): self._lbl_status.setText("Found GPU " + str(msg["id"]) + ": " + msg["name"]) else: self._lbl_status.setText("Found CPU: " + msg["name"]) else: self._lbl_status.setText("Scan failed: " + msg["error"]) def _socketClosed(self): self._quitScan() self._enable() self._lbl_status.setText("Connection lost!") def _quitScan(self): if hasattr(self, "ct"): self.ct.bufferReady.disconnect() self.ct.socketClosed.disconnect() self.ct.close() del self.ct def _getHardware(self): msg = {"key": Protocol.GETHARDWARE} ret = sendMsgToHost(self.host, self.port, msg) if ret and "hardware" in ret: return [ret["hardware"], ret["current"]] class HardwareListModel(QAbstractListModel): def __init__(self, data): QAbstractListModel.__init__(self) self.data = data def rowCount(self, parent=None, *args, **kwargs): return len(self.data) def data(self, index, role=None): row = index.row() if role == Qt.DisplayRole: if row == 0: return "CPU: " + self.data[row]["name"] return "GPU " + str( self.data[row]["id"]) + ": " + self.data[row]["name"]
class MusicPlayer(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.options = self.parent().options self.ffmpeg = self.options['paths']['ffmpeg_bin'] self.thumbnails = self.options['paths']['thumbnails'] self.thumb_width = self.options['thumbnail']['width'] self.thumb_height = self.options['thumbnail']['height'] self.jumping = False self.blocked = False self.durations = {} self.playback_value = 0 self.text = ["None", "Repeat", "Random"] self.playlist_list = [] self.values = [ QMediaPlaylist.Loop, QMediaPlaylist.CurrentItemInLoop, QMediaPlaylist.Random ] # Thumbnail widget self.image_label = QLabel() # Control widgets self.playButton = QToolButton(clicked=self.play) self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton = QToolButton(clicked=self.stop) self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop)) self.stopButton.setEnabled(False) self.playbackButton = QToolButton(clicked=self.playback_mode) self.playbackButton.setText(self.text[0]) self.nextButton = QToolButton(clicked=self.next_song) self.nextButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipForward)) self.previousButton = QToolButton(clicked=self.previous_song) self.previousButton.setIcon(self.style().standardIcon( QStyle.SP_MediaSkipBackward)) self.muteButton = QToolButton(clicked=self.mute_clicked) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume)) self.volumeSlider = QSlider(Qt.Horizontal, sliderMoved=self.change_volume) self.volumeSlider.setRange(0, 100) self.volumeSlider.setPageStep(1) self.volumeSlider.setValue(50) # Player and playlist setup self.player = QMediaPlayer() self.player.setVolume(50) self.player.stateChanged.connect(self.waveform) self.playlist = QMediaPlaylist() self.playlist.setPlaybackMode(self.values[0]) self.playlist.setCurrentIndex(1) self.player.setPlaylist(self.playlist) self.playlistModel = PlaylistModel() self.playlistModel.setPlaylist(self.playlist) self.playlistView = QListView() self.playlistView.setModel(self.playlistModel) self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) self.playlistView.activated.connect(self.jump) self.playlistView.setContextMenuPolicy(Qt.CustomContextMenu) self.playlistView.customContextMenuRequested.connect( self.list_view_menu) self.playlist.currentIndexChanged.connect( lambda position: self.change_thumbnail(position)) song_search = QLineEdit() song_search.textChanged.connect(self.search) song_search.setClearButtonEnabled(True) # Playlist self.playlist_name = QComboBox() self.playlist_name.currentTextChanged.connect(self.switch_playlist) self.refresh_lists() self.up_button = QToolButton(clicked=self.move_up) self.up_button.setIcon(self.style().standardIcon(QStyle.SP_ArrowUp)) self.down_button = QToolButton(clicked=self.move_down) self.down_button.setIcon(self.style().standardIcon( QStyle.SP_ArrowDown)) # Sound wave widget self.wave_graphic = WaveGraphic(self) #self.wave_graphic.hide() # Testing slider again self.slider = QSlider(Qt.Horizontal) self.slider.setRange(0, self.player.duration() / 1000) self.slider.sliderMoved.connect(self.seek) self.player.durationChanged.connect(self.durationChanged) self.player.positionChanged.connect(self.positionChanged) # Shortcuts QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self, song_search.setFocus) # Layouts setup playlist_layout = QHBoxLayout() playlist_layout.addWidget(self.playlist_name) playlist_layout.addWidget(self.up_button) playlist_layout.addWidget(self.down_button) control_layout = QHBoxLayout() control_layout.setContentsMargins(0, 0, 0, 0) control_layout.addWidget(self.stopButton) control_layout.addWidget(self.previousButton) control_layout.addWidget(self.playButton) control_layout.addWidget(self.nextButton) control_layout.addWidget(self.muteButton) control_layout.addWidget(self.volumeSlider) control_layout.addWidget(self.playbackButton) display_layout = QVBoxLayout() display_layout.addWidget(song_search) display_layout.addWidget(self.playlistView) display_layout.addLayout(playlist_layout) music_layout = QVBoxLayout() music_layout.addWidget(self.image_label) music_layout.addWidget(self.slider) music_layout.addLayout(control_layout) main_layout = QHBoxLayout() main_layout.addLayout(music_layout) main_layout.addLayout(display_layout) main_2_layout = QVBoxLayout() main_2_layout.addLayout(main_layout) main_2_layout.addWidget(self.wave_graphic) self.setLayout(main_2_layout) def waveform(self, status): if status == QMediaPlayer.PlayingState: self.wave_graphic.start() elif status == QMediaPlayer.PausedState: self.wave_graphic.pause() else: self.wave_graphic.stop() def list_view_menu(self, point): menu = QMenu("Menu", self) recommend_action = QAction('&Recommend Songs', self) menu.addAction(recommend_action) # TODO: [FEATURE] add rename song recommend_action.triggered.connect( lambda: self.parent().call_download_manager(self.get_links())) rename_action = QAction('&Rename', self) menu.addAction(rename_action) # TODO: [FEATURE] add rename song rename_action.triggered.connect(lambda: print("rename")) # Show the context menu. menu.exec_(self.playlistView.mapToGlobal(point)) def get_links(self): title = self.playlistView.selectedIndexes()[0].data() link = getYoutubeURLFromSearch(title) if len(link) > 1: return youtube_recommendations(link) def move_up(self): index = self.playlistView.currentIndex().row() if index - 1 >= 0: item, above = self.playlist.media(index), self.playlist.media( index - 1) self.playlist.removeMedia(index) self.playlist.removeMedia(index - 1) self.playlist.insertMedia(index - 1, item) self.playlist.insertMedia(index, above) self.blocked = True self.playlistView.setCurrentIndex( self.playlistModel.index(index - 1, 0)) self.blocked = False self.stop() def move_down(self): index = self.playlistView.currentIndex().row() if index + 1 <= self.playlistModel.rowCount(): item, below = self.playlist.media(index), self.playlist.media( index + 1) self.playlist.removeMedia(index + 1) self.playlist.removeMedia(index) self.playlist.insertMedia(index, below) self.playlist.insertMedia(index + 1, item) self.blocked = True self.playlistView.setCurrentIndex( self.playlistModel.index(index + 1, 0)) self.blocked = False self.stop() def search(self, part_of_song): for index in range(self.playlistModel.rowCount()): item = self.playlistModel.data(self.playlistModel.index( index, 0)).lower() self.playlistView.setRowHidden(index, part_of_song.lower() not in item) def change_thumbnail(self, position=0): self.playlistView.setCurrentIndex(self.playlistModel.index( position, 0)) song = self.playlistView.selectedIndexes()[0].data() if self.wave_graphic.is_song_cached(song): self.wave_graphic.load_waves(song) else: wc_ = WaveConverter(song, self.wave_graphic.set_wav) wc_.convert() if self.playlistView.currentIndex().data() is None or self.blocked: return max_ratio = 0 img = None for item in listdir(self.thumbnails): if item.endswith('.jpg'): ratio = similar( item, self.playlistView.currentIndex().data().replace( '.mp3', '.jpg')) if ratio > max_ratio: max_ratio = ratio img = item if img: p = QPixmap(self.thumbnails + img) self.image_label.setPixmap( p.scaled(self.thumb_width, self.thumb_height, Qt.KeepAspectRatio)) def switch_playlist(self, current_text): self.playlist.clear() if current_text == "No Playlist": self.refresh() else: if read_playlist(current_text): songs = read_playlist(current_text).split('\n') for song in songs: self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(song))) def refresh(self): # Change it so it will go to same song. if self.playlist_name.currentText() != "No Playlist": return paths = fetch_options()['paths']['music_path'].split(';') current_songs = [ self.playlistModel.data(self.playlistModel.index(row, 0)) for row in range(self.playlistModel.rowCount()) ] for path in paths: if not path: continue for item in listdir(path): if isfile(join(path, item)) and item.endswith(".mp3") and ( item not in current_songs): self.playlist.addMedia( QMediaContent(QUrl.fromLocalFile(join(path, item)))) def refresh_lists(self): path = fetch_options()['paths']['playlist'] self.playlist_name.clear() self.playlist_list = ["No Playlist"] self.playlist_name.addItem("No Playlist") for item in listdir(path): if isfile(join(path, item)) and item.endswith(".lst"): self.playlist_list.append(item.split('.')[0]) self.playlist_name.addItem(item.split('.')[0]) def playback_mode(self): # Normal -> Loop -> Random def up_value(value, max_value=3): if value + 1 == max_value: return 0 return value + 1 self.playback_value = up_value(self.playback_value) self.playlist.setPlaybackMode(self.values[self.playback_value]) self.playbackButton.setText(self.text[self.playback_value]) def jump(self, index): if index.isValid() and not self.blocked: self.playlist.setCurrentIndex(index.row()) self.jumping = True self.play() def play(self): if self.blocked: return if self.player.state() != QMediaPlayer.PlayingState or self.jumping: self.player.play() self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPause)) self.jumping = False else: self.player.pause() self.playButton.setIcon(self.style().standardIcon( QStyle.SP_MediaPlay)) self.stopButton.setEnabled(True) def change_volume(self, value): self.player.setVolume(value) def stop(self): if self.player.state() != QMediaPlayer.StoppedState: self.player.stop() self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay)) self.stopButton.setEnabled(False) def next_song(self): self.playlist.next() self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) def previous_song(self): self.playlist.previous() self.playlistView.setCurrentIndex( self.playlistModel.index(self.playlist.currentIndex(), 0)) def mute_clicked(self): self.player.setMuted(not self.player.isMuted()) self.muteButton.setIcon(self.style().standardIcon( QStyle.SP_MediaVolume if not self.player.isMuted() else QStyle. SP_MediaVolumeMuted)) def durationChanged(self, duration): duration /= 1000 self.slider.setMaximum(duration) def positionChanged(self, progress): progress /= 1000 if not self.slider.isSliderDown(): self.slider.setValue(progress) def seek(self, seconds): self.player.setPosition(seconds * 1000)
class ClientGui(QWidget): def __init__(self): self.service_msg_deq = [] # очередь сервисных сообщений, очищать! self.icon_user = QIcon("user.svg") self.icon_new_msg = QIcon("message.svg") super().__init__() self.get_login_dialog() def initUI(self): # Кнопки: добавить/удалить контакты в контакт лист self.button_add_contact = QPushButton('add', self) self.button_add_contact.clicked.connect(self.add_contact) self.button_del_contact = QPushButton('del', self) self.button_del_contact.clicked.connect(self.del_contact) self.button_settings = QPushButton('men', self) self.button_settings.setEnabled(False) # не работает self.button_connect = QPushButton('conn', self) self.button_connect.setEnabled(False) # не работает self.box_button = QHBoxLayout() self.box_button.addWidget(self.button_add_contact) self.box_button.addWidget(self.button_del_contact) self.box_button.addWidget(self.button_settings) self.box_button.addWidget(self.button_connect) # создаю модель для листа контактов, подключаю отображение cl = bd_client_app.BDContacts().get_contacts() self.model_cl = QStandardItemModel() for user in cl: row = QStandardItem(self.icon_user, user) self.model_cl.appendRow(row) self.contact_list = QListView() self.contact_list.setModel(self.model_cl) self.contact_list.setSelectionMode(QListView.SingleSelection) self.contact_list.setEditTriggers(QListView.NoEditTriggers) self.contact_list.clicked.connect(self.select_conlist) # строка и кнопка отправки сообщений qButton = QPushButton('>>', self) qButton.clicked.connect(self.send_click) self.sendBox = QLineEdit(self) self.sendBox.returnPressed.connect(self.send_click) self.messageBox = QStackedWidget() # два словаря, в первом: логин ключ виджет значение, второй наоборот self.messageBox_dict_ctw = {} self.messageBox_dict_wtc = {} for user in cl: self.messageBox_dict_ctw[user] = QListWidget() self.messageBox_dict_wtc[self.messageBox_dict_ctw[user]] = user self.messageBox.addWidget(self.messageBox_dict_ctw[user]) grid = QGridLayout() # строка, столбец, растянуть на строк, растянуть на столбцов grid.addWidget(self.contact_list, 0, 0, 2, 3) grid.addLayout(self.box_button, 2, 0) grid.addWidget(self.messageBox, 0, 3, 2, 3) grid.addWidget(self.sendBox, 2, 3, 1, 2) grid.addWidget(qButton, 2, 5) grid.setSpacing(5) grid.setColumnMinimumWidth(3, 200) grid.setColumnStretch(3, 10) self.setLayout(grid) self.resize(800, 300) self.center() self.setWindowTitle('Avocado') self.setWindowIcon(QIcon('icon.svg')) self.show() def initThreads(self): self.print_thread = ClientThreads(self.client, self) self.print_thread.print_signal.connect(self.add_message) self.print_thread.start() def get_login_dialog(self): text, ok = QInputDialog.getText(self, 'Login', 'Connect with login:') self.login_name = str(text) if ok: self.service_msg_deq.clear() # жду свой ответ self.init_client() self.initThreads() # while not self.service_msg_deq: # print(self.service_msg_deq) # pass # жду ответ # if self.service_msg_deq[0] is True: time.sleep(1) self.initUI() # else: # self.exit() else: self.exit() def init_client(self): self.client = client.Client(self.login_name, "localhost", 7777) self.client.start_th_gui_client() def center(self): # центрирую окно qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) @pyqtSlot() def send_click(self): text_to_send = self.sendBox.text() if text_to_send.rstrip(): self.messageBox.currentWidget().addItem("<< " + text_to_send) self.client.inp_queue.put(text_to_send) self.sendBox.clear() @pyqtSlot(QModelIndex) def select_conlist(self, curr): self.messageBox.setCurrentIndex(curr.row()) self.model_cl.itemFromIndex(curr).setIcon(self.icon_user) self.client.to_user = self.messageBox_dict_wtc[ self.messageBox.currentWidget()] @pyqtSlot(tuple) def add_message(self, message): msg = message[0] from_u = message[1] try: client_widget = self.messageBox_dict_ctw[from_u] except KeyError: mesg_con_log.error("Message from user from not in contact list:") mesg_con_log.error("%s, %s" % (from_u, msg)) else: client_widget.addItem(">> " + msg) message_from = self.model_cl.findItems(from_u)[0] if self.contact_list.currentIndex() != self.model_cl.indexFromItem( message_from): message_from.setIcon(self.icon_new_msg) @pyqtSlot() def del_contact(self): user = self.client.to_user self.client.inp_queue.put("del_contact " + user) self.messageBox.removeWidget(self.messageBox_dict_ctw[user]) self.model_cl.takeRow( self.model_cl.indexFromItem( self.model_cl.findItems(user)[0]).row()) @pyqtSlot() def add_contact(self): user = self.sendBox.text() self.service_msg_deq.clear() # жду свой ответ self.client.inp_queue.put("add_contact " + user) while not self.service_msg_deq: pass # жду ответ if self.service_msg_deq[0] is True: row = QStandardItem(self.icon_user, user) self.model_cl.appendRow(row) self.messageBox_dict_ctw[user] = QListWidget() self.messageBox_dict_wtc[self.messageBox_dict_ctw[user]] = user self.messageBox.addWidget(self.messageBox_dict_ctw[user]) else: pass self.sendBox.clear()
class MainWindow(QMainWindow): logout_signal = pyqtSignal() send_message_signal = pyqtSignal(str, str) start_chatting_signal = pyqtSignal(str) switch_to_add_contact = pyqtSignal() switch_to_del_contact = pyqtSignal() def __init__(self, client_name): super().__init__() self.setFixedSize(756, 574) self.setWindowTitle(f'Python Messenger ({client_name})') central_widget = QWidget() self.label_contacts = QLabel('Contact list:', central_widget) self.label_contacts.setGeometry(QRect(10, 0, 101, 16)) self.add_contact_btn = QPushButton('Add contact', central_widget) self.add_contact_btn.setGeometry(QRect(10, 450, 121, 31)) self.remove_contact_btn = QPushButton('Remove contact', central_widget) self.remove_contact_btn.setGeometry(QRect(140, 450, 121, 31)) self.label_history = QLabel('Chat room:', central_widget) self.label_history.setGeometry(QRect(300, 0, 391, 21)) self.text_message = QTextEdit(central_widget) self.text_message.setGeometry(QRect(300, 360, 441, 71)) self.label_new_message = QLabel('Enter message here:', central_widget) self.label_new_message.setGeometry(QRect(300, 330, 450, 16)) self.toolbar = self.addToolBar('Formatting') self.char_style_resolver = { 'bold': self.set_text_to_bold, 'italic': self.set_text_to_italic, 'underline': self.set_text_to_underline, } self.font_weight = 50 self.font_italic = False self.font_underline = False self.text_font = QFont() self.text_bold = QAction(QIcon('client/ui/icons/b.jpg'), 'Bold', self) self.text_bold.triggered.connect(lambda: self.set_char_style('bold')) self.text_italic = QAction(QIcon('client/ui/icons/i.jpg'), 'Italic', self) self.text_italic.triggered.connect( lambda: self.set_char_style('italic')) self.text_underline = QAction(QIcon('client/ui/icons/u.jpg'), 'Underline', self) self.text_underline.triggered.connect( lambda: self.set_char_style('underline')) self.toolbar.addActions( [self.text_bold, self.text_italic, self.text_underline]) self.list_contacts = QListView(central_widget) self.list_contacts.setGeometry(QRect(10, 20, 251, 411)) self.contacts_model = QStandardItemModel() self.list_contacts.setModel(self.contacts_model) self.list_messages = QListView(central_widget) self.list_messages.setGeometry(QRect(300, 20, 441, 301)) self.messages_model = QStandardItemModel() self.list_messages.setModel(self.messages_model) self.is_list_messages_disable = False self.send_btn = QPushButton('Send', central_widget) self.send_btn.setGeometry(QRect(610, 450, 131, 31)) self.clear_btn = QPushButton('Clear', central_widget) self.clear_btn.setGeometry(QRect(460, 450, 131, 31)) self.setCentralWidget(central_widget) self.menubar = QMenuBar(self) self.menubar.setGeometry(QRect(0, 0, 756, 21)) self.menu = QMenu('File', self.menubar) self.menu_2 = QMenu('Contacts', self.menubar) self.setMenuBar(self.menubar) self.statusBar = QStatusBar(self) self.setStatusBar(self.statusBar) self.menu_exit = QAction('Exit', self) self.menu_logout = QAction('Logout', self) self.menu.addAction(self.menu_exit) self.menu.addAction(self.menu_logout) self.add_contact_menu = QAction('Add new', self) self.del_contact_menu = QAction('Remove some', self) self.menu_2.addAction(self.add_contact_menu) self.menu_2.addAction(self.del_contact_menu) self.menu_2.addSeparator() self.menubar.addAction(self.menu.menuAction()) self.menubar.addAction(self.menu_2.menuAction()) self.message = QMessageBox() self.menu_exit.triggered.connect(qApp.exit) self.menu_logout.triggered.connect(self.menu_logout_handler) self.send_btn.clicked.connect(self.send_btn_handler) self.add_contact_btn.clicked.connect(self.add_contact_btn_handler) self.add_contact_menu.triggered.connect(self.add_contact_btn_handler) self.remove_contact_btn.clicked.connect(self.del_contact_btn_handler) self.del_contact_menu.triggered.connect(self.del_contact_btn_handler) self.list_contacts.doubleClicked.connect( self.list_contacts_click_handler) def set_elements_disable_status(self, status): if not isinstance(status, bool): raise ValueError( f'Disable status must be bool. Got {type(status)}') self.send_btn.setDisabled(status) self.clear_btn.setDisabled(status) self.text_message.setDisabled(status) self.is_list_messages_disable = status def render_welcome_message(self): self.messages_model.clear() msg = QStandardItem( f'Doubleclick to contact in contact list for start chatting.') msg.setEditable(False) self.messages_model.appendRow(msg) def render_contacts(self, contacts): self.contacts_model.clear() if contacts and isinstance(contacts, list): for contact in contacts: rendered_contact = QStandardItem(contact.friend) rendered_contact.setEditable(False) self.contacts_model.appendRow(rendered_contact) def render_messages(self, friend, client_name, messages): self.messages_model.clear() if messages and isinstance(messages, list): for message in messages: self.render_message(friend, client_name, message) self.list_messages.scrollToBottom() def render_message(self, friend, client_name, message): if not self.is_list_messages_disable: if message.from_client in (friend, client_name): date = message.created.replace(microsecond=0) text = message.text from_client = message.from_client msg = QStandardItem(f'{date}\n{from_client}:\n{text}') msg.setEditable(False) if from_client == client_name: msg.setTextAlignment(Qt.AlignRight) msg.setBackground(QBrush(QColor(240, 240, 240))) self.messages_model.appendRow(msg) self.list_messages.scrollToBottom() def menu_logout_handler(self): self.logout_signal.emit() def send_btn_handler(self): message = self.text_message.toPlainText() to_client_name = self.list_contacts.currentIndex().data() if message and to_client_name: self.send_message_signal.emit(to_client_name, message) self.text_message.clear() def add_contact_btn_handler(self): self.switch_to_add_contact.emit() def del_contact_btn_handler(self): self.switch_to_del_contact.emit() def list_contacts_click_handler(self): self.messages_model.clear() self.set_elements_disable_status(False) friend = self.list_contacts.currentIndex().data() self.start_chatting_signal.emit(friend) def set_char_style(self, style): cursor = self.text_message.textCursor() char_format = QTextCharFormat() self.char_style_resolver[style](char_format) cursor.mergeCharFormat(char_format) def set_text_to_bold(self, char_format): bold_weight = 600 thin_weight = 50 weight = bold_weight if self.font_weight < bold_weight else thin_weight char_format.setFontWeight(weight) self.font_weight = weight def set_text_to_italic(self, char_format): char_format.setFontItalic(not self.font_italic) self.font_italic = not self.font_italic def set_text_to_underline(self, char_format): char_format.setFontUnderline(not self.font_underline) self.font_underline = not self.font_underline
class PwdManager(QDialog): def __init__(self): super().__init__() self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowTitleHint) self.setWindowTitle('Password Manager') self.setFixedSize(400, 300) self.PwdViewer = QListView() self.PwdViewer.clicked.connect(self.ClickPwd) self.AddButton = QPushButton('Add') self.AddButton.clicked.connect(self.AddPwd) self.DelButton = QPushButton('Delete') self.DelButton.clicked.connect(self.DelPwd) self.PwdBox = QLineEdit() self.PwdBox.textEdited.connect(self.PwdChanged) vbox = QVBoxLayout() vbox.addWidget(self.AddButton) vbox.addWidget(self.DelButton) vbox.addStretch(1) hbox = QHBoxLayout() hbox.addWidget(self.PwdViewer) hbox.addLayout(vbox) MainBox = QVBoxLayout() MainBox.addWidget(self.PwdBox) MainBox.addLayout(hbox) self.setLayout(MainBox) def showEvent(self, event): self.center() self.LoadPwdToList() if self.Model.rowCount() == 0: self.AddPwd() self.IsChanged = False def closeEvent(self, event): self.RemoveEmpty() pwdf = open('password.pwd', 'w') for index in range(self.Model.rowCount()): pwdf.write(self.Model.data(self.Model.index(index, 0)) + '\n') pwdf.close() if self.IsChanged: self.done(1) else: self.done(0) def center(self): frameGm = self.frameGeometry() screen = QApplication.desktop().screenNumber( QApplication.desktop().cursor().pos()) centerPoint = QApplication.desktop().screenGeometry(screen).center() frameGm.moveCenter(centerPoint) self.move(frameGm.topLeft()) def LoadPwdToList(self): if not os.path.exists(r'password.pwd'): open("password.pwd", "wb").close() pwdf = open('password.pwd', 'r') pwdlist = pwdf.read().splitlines() pwdf.close() self.Model = QStandardItemModel(self.PwdViewer) for pwd in pwdlist: item = QStandardItem(pwd) item.setEditable(False) self.Model.appendRow(item) self.PwdViewer.setModel(self.Model) self.PwdViewer.setCurrentIndex(self.Model.index(0, 0)) self.GetPwd(self.PwdViewer.currentIndex()) def ClickPwd(self, index): self.RemoveEmpty() if self.Model.rowCount() == 0: self.AddPwd() self.GetPwd(index) def GetPwd(self, index): self.PwdBox.setText(self.Model.data(index)) self.PwdBox.setFocus() def PwdChanged(self): self.IsChanged = True self.Model.setData(self.PwdViewer.currentIndex(), self.PwdBox.text()) if self.PwdBox.text() == '': self.DelPwd() def DelPwd(self): self.Model.removeRow(self.PwdViewer.currentIndex().row()) self.GetPwd(self.PwdViewer.currentIndex()) if self.Model.rowCount() == 0: self.AddPwd() def AddPwd(self): item = QStandardItem() item.setEditable(False) self.Model.appendRow(item) self.PwdViewer.setCurrentIndex( self.Model.index(self.Model.rowCount() - 1, 0)) self.GetPwd(self.PwdViewer.currentIndex()) def RemoveEmpty(self): for item in self.Model.findItems('', Qt.MatchFixedString): self.Model.removeRow(item.row())
class Documents_Tab(QWidget): def __init__(self): super(QWidget, self).__init__() self.main_layout = QGridLayout() self.setLayout(self.main_layout) self.tree_labels = QWidget() self.tree_labels_layout = QHBoxLayout() self.tree_labels.setLayout(self.tree_labels_layout) self.documents_tree_label = QLabel("List of Documents for Group:") self.documents_tree_label.setAlignment(Qt.AlignRight) self.documents_tree_group = QLabel("My Group") self.documents_tree_group.setAlignment(Qt.AlignLeft) self.tree_labels_layout.addWidget(self.documents_tree_label) self.tree_labels_layout.addWidget(self.documents_tree_group) self.tree_labels_layout.setAlignment(Qt.AlignCenter) self.documents_tree = QListView() self.documents_tree_model = QStandardItemModel() self.documents_tree.setModel(self.documents_tree_model) # self.documents_tree_model.appendRow(StandardItem("medsssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss")) #self.documents_tree.setGeometry(30,10,200,400) self.create_doc_widget = QWidget() self.create_doc_widget_layout = QVBoxLayout() self.create_doc_widget.setLayout(self.create_doc_widget_layout) self.create_doc_edits_widget = QWidget() self.create_doc_edits_widget_layout = QHBoxLayout() self.create_doc_edits_widget.setLayout(self.create_doc_edits_widget_layout) self.create_doc_label = QLabel("Create a Document") self.create_doc_label.setAlignment(Qt.AlignCenter) self.create_doc_edit = QLineEdit() self.create_doc_button = QPushButton("Create") self.create_doc_button.clicked.connect(lambda: self.create_doc(self.create_doc_edit.text())) self.create_doc_edits_widget_layout.addWidget(self.create_doc_edit) self.create_doc_edits_widget_layout.addWidget(self.create_doc_button) self.create_doc_widget_layout.addWidget(self.create_doc_label) self.create_doc_widget_layout.addWidget(self.create_doc_edits_widget) ########################################################################### self.share_doc_widget = QWidget() self.share_doc_widget_layout = QVBoxLayout() self.share_doc_widget.setLayout(self.share_doc_widget_layout) self.share_doc_edits_widget = QWidget() self.share_doc_edits_widget_layout = QHBoxLayout() self.share_doc_edits_widget.setLayout(self.share_doc_edits_widget_layout) self.share_doc_label = QLabel("Share a Document") self.share_doc_label.setAlignment(Qt.AlignCenter) self.share_doc_edit = QLineEdit() self.share_doc_button = QPushButton("Share") self.share_doc_button.clicked.connect(lambda: self.share_doc(self.share_doc_edit.text())) self.share_doc_edits_widget_layout.addWidget(self.share_doc_edit) self.share_doc_edits_widget_layout.addWidget(self.share_doc_button) self.share_doc_widget_layout.addWidget(self.share_doc_label) self.share_doc_widget_layout.addWidget(self.share_doc_edits_widget) ########################################################################### self.delete_doc_widget = QWidget() self.delete_doc_widget_layout = QVBoxLayout() self.delete_doc_widget.setLayout(self.delete_doc_widget_layout) self.delete_doc_edits_widget = QWidget() self.delete_doc_edits_widget_layout = QHBoxLayout() self.delete_doc_edits_widget.setLayout(self.delete_doc_edits_widget_layout) self.delete_doc_label = QLabel("Delete a Document") self.delete_doc_label.setAlignment(Qt.AlignCenter) self.delete_doc_edit = QLineEdit() self.delete_doc_button = QPushButton("Delete") self.delete_doc_button.clicked.connect(lambda: self.delete_doc(self.delete_doc_edit.text())) self.delete_doc_edits_widget_layout.addWidget(self.delete_doc_edit) self.delete_doc_edits_widget_layout.addWidget(self.delete_doc_button) self.delete_doc_widget_layout.addWidget(self.delete_doc_label) self.delete_doc_widget_layout.addWidget(self.delete_doc_edits_widget) ########################################################################### self.main_layout.addWidget(self.tree_labels) self.main_layout.addWidget(self.documents_tree) self.main_layout.addWidget(self.create_doc_widget) self.main_layout.addWidget(self.share_doc_widget) self.main_layout.addWidget(self.delete_doc_widget) @pyqtSlot() def switch_group(self, group): #emit signal to group widget needed self.documents_tree_group.setText(group) @pyqtSlot() def get_group_docs(self): # db call to groups docs pass @pyqtSlot() def create_doc(self, text): if text == "": error = "No name for creating a doc" else: print("creating doc:", text) self.add_doc_to_list(text) self.create_doc_edit.setText("") @pyqtSlot() def share_doc(self, text): if text == "": error = "No link for sharing a doc" else: print("sharing doc:", text) self.add_doc_to_list(text) self.share_doc_edit.setText("") @pyqtSlot() def delete_doc(self, text): if text == "": error = "No name for sharing a doc" else: print("deleting doc", text) self.delete_doc_edit.setText("") @pyqtSlot() def add_doc_to_list(self, doc): link = StandardItem(doc) self.documents_tree_model.appendRow(link) def contextMenuEvent(self, event): contextMenu = QMenu(self.documents_tree) newAct = contextMenu.addAction("Delete Doc") action = contextMenu.exec_(self.mapToGlobal(event.pos())) if action == newAct: index = self.documents_tree.currentIndex() itemText = index.data() itemRow = index.row() self.documents_tree_model.removeRow(itemRow) print(itemText) print(itemRow)
class NameList(QDockWidget): def __init__(self, window): super(NameList, self).__init__('Current Plots') self.namelist_model = QStandardItemModel() self.namelist_view = QListView() self.namelist_view.setModel(self.namelist_model) self.setWidget(self.namelist_view) self.window = window self.plot_dict = {} self.namelist_view.doubleClicked.connect(self.activate_item) self.namelist_view.setContextMenuPolicy(QtConst.ActionsContextMenu) delete_action = QAction("Delete Selected", self.namelist_view) ### pause_action = QAction("Stop Script", self.namelist_view) delete_action.triggered.connect(self.delete_item) pause_action.triggered.connect(self.pause) self.namelist_view.addAction(delete_action) self.namelist_view.addAction(pause_action) open_action = QAction('Open 1D Data', self) open_action.triggered.connect(self.open_file_dialog) self.namelist_view.addAction(open_action) open_action_2 = QAction('Open 2D Data', self) open_action_2.triggered.connect(self.open_file_dialog_2) self.namelist_view.addAction(open_action_2) def open_file_dialog(self, directory='', header=0): file_path = self.file_dialog(directory=directory) header_array = [] file_to_read = open(file_path, 'r') for i, line in enumerate(file_to_read): if i is header: break temp = line.split(":") header_array.append(temp) file_to_read.close() temp = np.genfromtxt(file_path, dtype=float, delimiter=',', skip_header=1) data = np.transpose(temp) name_plot = datetime.now().strftime('%Y-%m-%d %H:%M:%S') pw = self.window.add_new_plot(1, name_plot) pw.plot(data[0], data[1], parametric=True, name=file_path, xname='X', xscale ='Arb. U.',\ yname='Y', yscale ='Arb. u.', scatter='False') def open_file_dialog_2(self, directory='', header=0): file_path = self.file_dialog(directory=directory) header_array = [] file_to_read = open(file_path, 'r') for i, line in enumerate(file_to_read): if i is header: break temp = line.split(":") header_array.append(temp) file_to_read.close() temp = np.genfromtxt(file_path, dtype=float, delimiter=',') data = temp name_plot = datetime.now().strftime('%Y-%m-%d %H:%M:%S') pw = self.window.add_new_plot(2, name_plot) pw.setAxisLabels(xname='X', xscale ='Arb. U.',yname='X', yscale ='Arb. U.',\ zname='X', zscale ='Arb. U.') pw.setImage(data, axes={'y': 0, 'x': 1}) def file_dialog(self, directory=''): root = tkinter.Tk() root.withdraw() file_path = filedialog.askopenfilename(**dict( initialdir = directory, filetypes = [("CSV", "*.csv"), ("TXT", "*.txt"),\ ("DAT", "*.dat"), ("all", "*.*")], title = 'Select file to open') ) return file_path def activate_item(self, index): item = self.namelist_model.itemFromIndex(index) plot = self.plot_dict[str(item.text())] if plot.closed: plot.closed = False self.window.add_plot(plot) def delete_item(self): index = self.namelist_view.currentIndex() item = self.namelist_model.itemFromIndex(index) del self[str(item.text())] def pause(self): sock = socket.socket() sock.connect(('localhost', 9091)) sock.send(b'Script stopped') sock.close() def __getitem__(self, item): return self.plot_dict[item] def __setitem__(self, name, plot): model = QStandardItem(name) model.setEditable(False) self.namelist_model.appendRow(model) self.plot_dict[name] = plot def __contains__(self, value): return value in self.plot_dict def __delitem__(self, name): self.namelist_model.removeRow( self.namelist_model.findItems(name)[0].index().row()) self.plot_dict[name].close() del self.plot_dict[name] def keys(self): return list(self.plot_dict.keys())
class MemoryMappingWidget(QDockWidget): def __init__(self, parent, *args, **kwargs): super(MemoryMappingWidget, self).__init__("Memory map", parent) self.log = self.parentWidget().log layout = QVBoxLayout() self.__memory_mapping = [ MemorySection(".text", 0x00004000, 0x1000, "READ|EXEC"), MemorySection(".data", 0x00005000, 0x1000, "READ|WRITE"), MemorySection(".stack", 0x00006000, 0x4000, "READ|WRITE"), MemorySection(".misc", 0x0000a000, 0x1000, "ALL"), ] self.model = QStringListModel() self.model.setStringList(self.memory_mapping_str) self.view = QListView() self.view.setModel(self.model) layout.addWidget(self.view) buttons = QHBoxLayout() btn_add = QPushButton("Add Section") buttons.addWidget(btn_add) btn_add.clicked.connect(self.onAddSectionButtonClicked) buttons.addStretch(1) btn_del = QPushButton("Remove Section") btn_del.clicked.connect(self.onDeleteSectionButtonClicked) buttons.addWidget(btn_del) layout.addLayout(buttons) w = QWidget(self) w.setLayout(layout) self.setWidget(w) return @property def memory_mapping_str(self) -> None: """ Generator for the string view model """ for entry in self.__memory_mapping: yield str(entry) def updateView(self) -> bool: """ Refresh the view """ self.model.setStringList(self.memory_mapping_str) return True @property def maps(self) -> List[MemorySection]: """ Exports the memory mapping to a format usable for Unicorn """ self.__maps = self.__memory_mapping[::] return self.__maps def onAddSectionButtonClicked(self) -> None: """ Callback associated with the click of the "Add Section" button """ self.add_or_edit_section_popup() return def onDeleteSectionButtonClicked(self) -> None: """ Callback associated with the click of the "Remove Section" button """ idx = self.view.currentIndex() line_content = idx.data() for i, sect in enumerate(self.__memory_mapping): if line_content == str(sect): if self.__memory_mapping[i].name in (".text", ".data", ".stack"): print("cannot delete required section '{}'".format( self.__memory_mapping[i].name)) break del self.__memory_mapping[i] self.updateView() break return def add_or_edit_section_popup(self) -> None: """ Popup that present a form with all info to submit to create a new section """ msgbox = QMessageBox(self) wid = QWidget() name = QLabel("Name") nameEdit = QLineEdit() startAddress = QLabel("Start Address (hex)") startAddressEdit = QLineEdit() size = QLabel("Size (hex)") sizeEdit = QLineEdit() perm = QLabel("Permissions") permCheck = QWidget() permCheckLayout = QHBoxLayout() perm_read_btn = QCheckBox("R") perm_write_btn = QCheckBox("W") perm_exec_btn = QCheckBox("X") permCheckLayout.addWidget(perm_read_btn) permCheckLayout.addWidget(perm_write_btn) permCheckLayout.addWidget(perm_exec_btn) permCheck.setLayout(permCheckLayout) grid = QGridLayout() grid.setSpacing(10) grid.addWidget(name, 1, 0) grid.addWidget(nameEdit, 1, 1) grid.addWidget(startAddress, 2, 0) grid.addWidget(startAddressEdit, 2, 1) grid.addWidget(size, 3, 0) grid.addWidget(sizeEdit, 3, 1) grid.addWidget(perm, 4, 0) grid.addWidget(permCheck, 4, 1) msgbox.setLayout(grid) msgbox.setGeometry(300, 300, 350, 300) msgbox.setWindowTitle("Add/edit section") layout = msgbox.layout() wid.setLayout(grid) wid.setMinimumWidth(400) layout.addWidget(wid) msgbox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) ret = msgbox.exec() if ret == QMessageBox.Ok: section_name = nameEdit.text() section_address = int(startAddressEdit.text(), 16) section_size = int(sizeEdit.text(), 16) section_perm = [] if perm_read_btn.isChecked(): section_perm.append("READ") if perm_write_btn.isChecked(): section_perm.append("WRITE") if perm_exec_btn.isChecked(): section_perm.append("EXEC") section = MemorySection(section_name, section_address, section_size, "|".join(section_perm)) self.__memory_mapping.append(section) self.updateView() return
class CollectData(QWidget): def __init__(self): super().__init__() self.init_variable() self.init_img() self.init_ui() self.show() def init_img(self): self.qlabel = myLabel(self) img = cv2.imread('data/test.png') # 打开图片 self.qlabel.img = img.copy() self.qlabel.img_current = img.copy() self.update_img() def init_variable(self): self.label = 0 self.transformation_type = 0 self.total_img_number = 0 self.current_img_index = 0 self.folder_path = r"data" self.jump_img_index = -1 self.img_list = [] self.img_name_list = [] def init_ui(self): self.setGeometry(200, 200, 1000, 800) self.setWindowTitle('数据标注') self.qlabel.setGeometry(QRect(30, 30, 640, 480)) self.init_buttons() for file_name in os.listdir(self.folder_path + '/'): img = cv2.imread(self.folder_path + '/' + file_name) if img is None: continue self.img_list.append(img) self.img_name_list.append( os.path.splitext(self.folder_path + '/' + file_name)[0]) #QMessageBox.information(self, 'complete', '图片加载完毕') self.total_img_number = len(self.img_list) self.current_img_index = 1 self.refresh_img() self.update_list() def init_buttons(self): self.previous_img_button = QPushButton("上一张图片", self) self.next_img_button = QPushButton("下一张图片", self) self.save_message_button = QPushButton("保存当前图片信息", self) self.show_message_button = QPushButton("显示当前图片信息", self) self.open_folder_button = QPushButton("打开文件夹", self) self.add_border_button = QPushButton("保存当前框", self) self.delete_border_button = QPushButton("删除选中框", self) self.img_folder_text = QLineEdit('data', self) self.goto_chosen_img_button = QPushButton("跳转图片", self) self.jump_img_text = QLineEdit('', self) self.show_index_message = QLabel(self) self.img_folder_text.selectAll() self.img_folder_text.setFocus() self.previous_img_button.setGeometry(30, 530, 150, 40) self.next_img_button.setGeometry(200, 530, 150, 40) self.save_message_button.setGeometry(370, 530, 150, 40) self.show_message_button.setGeometry(540, 530, 150, 40) self.img_folder_text.setGeometry(30, 590, 660, 40) self.open_folder_button.setGeometry(710, 590, 150, 40) self.jump_img_text.setGeometry(30, 650, 150, 40) self.goto_chosen_img_button.setGeometry(200, 650, 150, 40) self.show_index_message.setGeometry(30, 710, 200, 40) self.add_border_button.setGeometry(710, 380, 150, 40) self.delete_border_button.setGeometry(710, 440, 150, 40) self.previous_img_button.clicked.connect(self.previous_img) self.next_img_button.clicked.connect(self.next_img) self.save_message_button.clicked.connect(self.save_message) self.show_message_button.clicked.connect(self.show_message) self.open_folder_button.clicked.connect(self.open_folder) self.add_border_button.clicked.connect(self.save_current_border) self.delete_border_button.clicked.connect(self.delete_border) self.goto_chosen_img_button.clicked.connect(self.goto_chosen_img) self.label_combo = QComboBox(self) for i in range(len(LABEL_LIST)): self.label_combo.addItem(LABEL_LIST[i]) self.label_combo.move(900, 30) self.label_combo.activated[str].connect(self.label_on_activated) self.listview = QListView(self) self.listview.setGeometry(710, 30, 150, 320) self.listview.doubleClicked.connect(self.list_clicked) self.listview.setEditTriggers(QListView.NoEditTriggers) def previous_img(self): if self.current_img_index == 1: QMessageBox.information(self, 'warning', '已经是第一张啦') return self.current_img_index -= 1 self.refresh_img() def next_img(self): if self.current_img_index == self.total_img_number: QMessageBox.information(self, 'warning', '已经是最后一张啦') return self.current_img_index += 1 self.refresh_img() def show_message(self): if len(self.qlabel.rectangle_label) > 0: reply = QMessageBox.question(self, '确认', '当前有未保存信息,是否继续?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return self.qlabel.rectangle_label.clear() if os.path.isfile(self.img_name_list[self.current_img_index - 1] + '.csv') == False: QMessageBox.information(self, 'warning', '当前图片无信息') return message = pd.read_csv(self.img_name_list[self.current_img_index - 1] + '.csv', sep=',', header=None) message = np.array(message.T) message = message.astype(int) for i in range(len(message)): self.qlabel.rectangle_label.append( Rectangle(message[i][1], message[i][2], message[i][3], message[i][4], True, message[i][0])) self.update_list() self.refresh_img() QMessageBox.information(self, 'complete', '信息加载完毕') def open_folder(self): self.folder_path = self.img_folder_text.text() if os.path.isdir(self.folder_path) == False: QMessageBox.information(self, 'warning', '文件夹路径非法') return self.img_list.clear() self.img_name_list.clear() for file_name in os.listdir(self.folder_path + '/'): img = cv2.imread(self.folder_path + '/' + file_name) if img is None: continue self.img_list.append(img) self.img_name_list.append( os.path.splitext(self.folder_path + '/' + file_name)[0]) QMessageBox.information(self, 'complete', '图片加载完毕') self.total_img_number = len(self.img_list) self.current_img_index = 1 self.refresh_img() def goto_chosen_img(self): if int(self.jump_img_text.text()) <= 0 or int( self.jump_img_text.text()) > self.total_img_number: QMessageBox.information(self, 'warning', '已经是最后一张啦') return self.current_img_index = int(self.jump_img_text.text()) self.refresh_img() def refresh_img(self): img = self.img_list[self.current_img_index - 1] self.qlabel.img = img.copy() self.qlabel.update_qlabel_img() self.update_img() self.show_index_message.setText('一共' + str(self.total_img_number) + '张图片,当前第' + str(self.current_img_index) + '张图片') def label_on_activated(self): self.label = self.label_combo.currentIndex() def update_list(self): slm = QStringListModel() string_list = [] for i in range(len(self.qlabel.rectangle_label)): string_list.append( LABEL_LIST[self.qlabel.rectangle_label[i].label]) slm.setStringList(string_list) self.listview.setModel(slm) def list_clicked(self, qModelIndex): if self.qlabel.rectangle_label[ qModelIndex.row()].whether_display == True: self.qlabel.rectangle_label[ qModelIndex.row()].whether_display = False else: self.qlabel.rectangle_label[ qModelIndex.row()].whether_display = True self.qlabel.update_qlabel_img() self.update_img() def save_current_border(self): self.qlabel.save_current_border(self.label) self.qlabel.update_qlabel_img() self.update_img() self.update_list() def update_img(self): img_resize = cv2.resize( self.qlabel.img_current, (self.qlabel.qlabel_length, self.qlabel.qlabel_width)) height, width, bytesPerComponent = img_resize.shape bytesPerLine = 3 * width cv2.cvtColor(img_resize, cv2.COLOR_BGR2RGB, img_resize) QImg = QImage(img_resize.data, width, height, bytesPerLine, QImage.Format_RGB888) pixmap = QPixmap.fromImage(QImg) self.qlabel.setPixmap(pixmap) self.qlabel.setCursor(Qt.CrossCursor) def label_clicked(self): sender = self.sender() if sender == self.label_button: self.label = self.label_button.checkedId() def save_message(self): self.save_current_angle() img = cv2.imread('data/test.png') # 打开图片 self.qlabel.rectangle_label.clear() self.update_img() self.update_list() self.qlabel.img = img.copy() self.qlabel.img_current = img.copy() self.update_img() def save_current_angle(self): if os.path.isfile(self.img_name_list[self.current_img_index - 1] + '.csv'): reply = QMessageBox.question(self, '确认', '是否覆盖当前图片已保存信息?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return save_data = [] for i in range(5): save_data.append([]) if len(self.qlabel.rectangle_label) > 0: for i in range(len(self.qlabel.rectangle_label)): save_data[0].append(self.qlabel.rectangle_label[i].label) save_data[1].append(self.qlabel.rectangle_label[i].x0) save_data[2].append(self.qlabel.rectangle_label[i].x1) save_data[3].append(self.qlabel.rectangle_label[i].y0) save_data[4].append(self.qlabel.rectangle_label[i].y1) if np.shape(np.array(save_data)) != (5, 0): print(self.current_img_index) np.savetxt(self.img_name_list[self.current_img_index - 1] + '.csv', np.array(save_data), delimiter=',') def delete_border(self): if self.listview.currentIndex().row() > -1: self.qlabel.delete_border(self.listview.currentIndex().row()) self.qlabel.update_qlabel_img() self.update_img() self.update_list() else: QMessageBox.information(self, 'warning', '请先选中一行')
class JsonEdit(QWidget): def __init__(self, dataPath, ico, parent=None, flags=Qt.WindowCloseButtonHint): super(JsonEdit, self).__init__(parent, flags) self.setStyleSheet( '''JsonEdit{background:#272626}QLabel{color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;} QPushButton{border:0px;background:#4d4d4d;color:#ffffff;font-family: "Microsoft YaHei", SimHei, SimSun;font:11pt;} QPushButton:pressed{background:#606162;font:10pt;} QPushButton:checked{background:#70bbe4;} QPushButton:hover{border-style:solid;border-width:1px;border-color:#ffffff;} QLineEdit{background-color:#4d4d4d;color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;border:0px;padding-left:5px} QLineEdit:hover{border-style:solid;border-width:1px;border-color:#ffffff;padding-left:4px;} QListView{background-color:#4d4d4d;color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:12pt;} QComboBox:hover{border-style:solid;border-width:1px;border-color:#ffffff;padding-left:4px;} QComboBox{background-color:#4d4d4d;color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;padding-left:5px;border:0px;} QComboBox:drop-down{width:0px;} QComboBox:down-arrow{width:0px} QComboBox:selected{background-color:#606162;} QComboBox:QAbstractItemView::item{font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;} QComboBox:QAbstractItemView::item:selected{background-color:#606162;} QInputDialog{background-color:#272626;} QScrollBar:vertical{width:8px;background:rgba(0,0,0,0%);margin:0px,0px,0px,0px;padding-top:0px;padding-bottom:0px;} QScrollBar:handle:vertical{width:8px;background:rgba(0,0,0,25%);border-radius:0px;min-height:20;} QScrollBar:handle:vertical:hover{width:8px;background:rgba(0,0,0,50%);border-radius:0px;min-height:20;} QScrollBar:add-line:vertical{height:0px;width:0px;subcontrol-position:bottom;} QScrollBar:sub-line:vertical{height:0px;width:0px;subcontrol-position:top;} QScrollBar:add-page:vertical,QScrollBar:sub-page:vertical{background:rgba(0,0,0,10%);border-radius:0px;} QScrollBar:horizontal{height:8px;background:rgba(0,0,0,0%);margin:0px,0px,0px,0px;padding-top:0px;padding-bottom:0px;} QScrollBar:handle:horizontal{width:8px;background:rgba(0,0,0,25%);border-radius:0px;min-height:20;} QScrollBar:handle:horizontal:hover{width:8px;background:rgba(0,0,0,50%);border-radius:0px;min-height:20;} QScrollBar:add-line:horizontal{height:0px;width:0px;subcontrol-position:bottom;} QScrollBar:sub-line:horizontal{height:0px;width:0px;subcontrol-position:top;} QScrollBar:add-page:horizontal,QScrollBar:sub-page:horizontal{background:rgba(0,0,0,10%);border-radius:0px;}''' ) self.setWindowIcon(QIcon(ico)) self.isshow = False self.isBootyMode = False self.bootyName = '固源岩' self.selPanel = BootyChoice(self, ico) self.json = dataPath + '/schedule.json' self.scheduleAdd = { 'part': 'MAIN', 'chap': '', 'objLevel': '', 'times': '' } self.transEX = { 'ex1': '切尔诺伯格', 'ex2': '龙门外环', 'ex3': '龙门市区', 'ex4': '当期委托' } self.partList = ['主线', '物资筹备', '芯片搜索', '剿灭作战'] self.partListJson = ['MAIN', 'RS', 'PR', 'EX'] self.mainChapList = [ '序章', '第一章', '第二章', '第三章', '第四章', '第五章', '第六章', '第七章', '第八章' ] self.rsChapList = ['战术演习', '粉碎防御', '空中威胁', '货物运送', '资源保障'] self.prChapList = ['医疗重装', '术士狙击', '辅助先锋', '特种近卫'] self.exChapList = ['切尔诺伯格', '龙门外环', '龙门市区', '当期委托'] self.chapList = [ self.mainChapList, self.rsChapList, self.prChapList, self.exChapList ] self.selIndex = None self.grid = QGridLayout() self.lsv = QListView() #计划显示框 self.lsv.setFixedWidth(200) self.lsv.clicked.connect(self.clickSchedule) self.lsv.setContextMenuPolicy(Qt.CustomContextMenu) self.lsv.customContextMenuRequested.connect(self.lsvRearrange) self.actMoveUp = QAction('上移') self.actMoveUp.triggered.connect(self.moveUpLine) self.actMoveDown = QAction('下移') self.actMoveDown.triggered.connect(self.moveDownLine) self.actEdit = QAction('修改次数/个数') self.actEdit.triggered.connect(self.editLine) self.actDel = QAction('删除') self.actDel.triggered.connect(self.delLine) self.slm = QStringListModel() self.partCb = QComboBox() self.partCb.addItems(self.partList) self.partCb.activated[int].connect(self.changeChapList) self.partCb.setFixedSize(80, 40) self.partCb.setView(QListView()) self.chapCb = QComboBox() self.chapCb.addItems(self.mainChapList) self.chapCb.activated[int].connect(self.changeLevel1List) self.chapCb.setFixedSize(100, 40) self.chapCb.setView(QListView()) self.level1Cb = QComboBox() self.level1Cb.setFixedSize(60, 40) self.level1Cb.setView(QListView()) self.lineLable = QLabel() self.lineLable.setText('-') self.level2Edit = QLineEdit() self.level2Edit.setFixedSize(50, 40) self.timesLable = QLabel() self.timesLable.setText('次数:') self.timeEdit = QLineEdit() self.timeEdit.setFixedSize(50, 40) self.bootyModeBtn = QPushButton() self.bootyModeBtn.setCheckable(True) self.bootyModeBtn.setText('素材模式') self.bootyModeBtn.setFixedHeight(40) self.bootyModeBtn.clicked[bool].connect(self.setBootMode) self.bootySelBtn = QPushButton() self.bootySelBtn.setText('——') self.bootySelBtn.setFixedHeight(40) self.bootySelBtn.clicked.connect(self.selPanel.myShow) self.delBtn = QPushButton() self.delBtn.setText('删除') self.delBtn.clicked.connect(self.delLine) self.delBtn.setFixedHeight(40) self.clearBtn = QPushButton() self.clearBtn.setText('清空') self.clearBtn.clicked.connect(self.clearLine) self.clearBtn.setFixedHeight(40) self.addBtn = QPushButton() self.addBtn.setText('添加') self.addBtn.clicked.connect(self.addLine) self.addBtn.setFixedHeight(40) self.planCb = QComboBox() self.planCb.setFixedSize(200, 40) self.planCb.setView(QListView()) self.loadPlanBtn = QPushButton() self.loadPlanBtn.setText('加载配置') self.loadPlanBtn.setFixedHeight(40) self.loadPlanBtn.clicked.connect(self.loadPlan) self.addPlanBtn = QPushButton() self.addPlanBtn.setText('以当前配置新建') self.addPlanBtn.setFixedHeight(40) self.addPlanBtn.clicked.connect(self.addPlan) self.delPlanBtn = QPushButton() self.delPlanBtn.setText('删除此配置') self.delPlanBtn.setFixedHeight(40) self.delPlanBtn.clicked.connect(self.delPlan) self.listScheduleBefore = [] self.listSchedule = [] self.initJson() self.slm.setStringList(self.listSchedule) self.lsv.setModel(self.slm) self.lsv.setEditTriggers(QListView.NoEditTriggers) self.changeLevel1List(0) self.grid.addWidget(self.lsv, 0, 0, 3, 1) self.grid.addWidget(self.partCb, 0, 1, 1, 1) self.grid.addWidget(self.chapCb, 0, 2, 1, 1) self.grid.addWidget(self.level1Cb, 0, 3, 1, 1) self.grid.addWidget(self.lineLable, 0, 4, 1, 1) self.grid.addWidget(self.level2Edit, 0, 5, 1, 1) self.grid.addWidget(self.timesLable, 0, 6, 1, 1) self.grid.addWidget(self.timeEdit, 0, 7, 1, 1) self.grid.addWidget(self.bootyModeBtn, 1, 1, 1, 1) self.grid.addWidget(self.bootySelBtn, 1, 2, 1, 1) self.grid.addWidget(self.addBtn, 1, 3, 1, 5) self.grid.addWidget(self.delBtn, 2, 1, 1, 4) self.grid.addWidget(self.clearBtn, 2, 5, 1, 3) self.grid.addWidget(self.planCb, 3, 0, 1, 1) self.grid.addWidget(self.loadPlanBtn, 3, 1, 1, 1) self.grid.addWidget(self.addPlanBtn, 3, 2, 1, 3) self.grid.addWidget(self.delPlanBtn, 3, 5, 1, 3) self.setLayout(self.grid) self.setWindowTitle('路线规划') #self.resize(600,400) self.myTimer() #self.show() def editerShow(self): if not self.isVisible(): self.show() cp = QDesktopWidget().availableGeometry().center() self.move(int(cp.x() - self.width() / 2), int(cp.y() - self.height() / 2)) def myTimer(self): self.updateTimer = QTimer() self.updateTimer.timeout.connect(self.updateList) self.updateTimer.start(10) def lsvRearrange(self): self.selIndex = self.lsv.currentIndex().row() rightClickMeun = QMenu() rightClickMeun.setStyleSheet( '''QMenu {color:#ffffff;font-family: "Microsoft YaHei", SimHei, SimSun;font:10pt; background-color:#272626; margin:3px;} QMenu:item {padding:8px 32px;} QMenu:item:selected { background-color: #3f4140;} QMenu:icon{padding: 8px 20px;} QMenu:separator{background-color: #7C7C7C; height:1px; margin-left:2px; margin-right:2px;}''' ) rightClickMeun.addAction(self.actMoveUp) rightClickMeun.addAction(self.actMoveDown) rightClickMeun.addAction(self.actEdit) rightClickMeun.addAction(self.actDel) rightClickMeun.exec_(QCursor.pos()) def initJson(self): with open(self.json, 'r', encoding='UTF-8') as s: data = s.read() self.jsonAll = loads(data)["main"] self.selPlan = self.jsonAll[0] self.allPlanList = self.selPlan['allplan'].split('|') #配置选单显示 self.planCb.addItems(self.allPlanList) self.jsonDict = self.jsonAll[0]['sel'] self.selList = self.jsonDict.copy() self.refreshJsonView() def refreshJsonView(self): self.listSchedule = [] for eachDict in self.selList: temp = eachDict['objLevel'] if 'ex' in temp: temp = self.transEX[temp] if eachDict['chap'] == 'LS': temp = temp.replace('S', 'LS') if isinstance(eachDict['times'], dict): self.listSchedule.append('{0}({1}共{2}个)'.format( temp, eachDict['times']['bootyName'], eachDict['times']['bootyNum'])) else: self.listSchedule.append('{0}(共{1}次)'.format( temp, eachDict['times'])) def updateJson(self): self.jsonAll[0]['sel'] = self.selList.copy() self.jsonAll[0]['allplan'] = '|'.join(self.allPlanList) #self.jsonAll[0]['selno'] = str(self.selNo) tempNewJson = {'main': self.jsonAll} newData = dumps(tempNewJson, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False) with open(self.json, 'w', encoding='UTF-8') as j: j.write(newData) def updateList(self): if self.listSchedule != self.listScheduleBefore: self.listScheduleBefore = self.listSchedule.copy() self.slm.setStringList(self.listSchedule) self.updateJson() def changeChapList(self, indexI): self.scheduleAdd['part'] = self.partListJson[indexI] self.chapCb.clear() self.chapCb.addItems(self.chapList[indexI]) self.changeLevel1List(0) def changeLevel1List(self, indexI): self.level1Cb.clear() selChap = self.chapCb.currentText() self.level2Edit.setReadOnly(False) levelList = [] if '章' in selChap: self.scheduleAdd['chap'] = str(int(indexI)) if int(indexI) != 8: levelList.append(f'{int(indexI)}') if int(indexI) != 0 and int(indexI) != 1: if int(indexI) != 8: levelList.append(f'S{int(indexI)}') elif int(indexI) == 8: levelList.extend([ f'R{int(indexI)}', f'M{int(indexI)}', f'JT{int(indexI)}' ]) elif selChap == '战术演习': self.scheduleAdd['chap'] = 'LS' levelList.append('LS') elif selChap == '粉碎防御': self.scheduleAdd['chap'] = 'AP' levelList.append('AP') elif selChap == '空中威胁': self.scheduleAdd['chap'] = 'CA' levelList.append('CA') elif selChap == '货物运送': self.scheduleAdd['chap'] = 'CE' levelList.append('CE') elif selChap == '资源保障': self.scheduleAdd['chap'] = 'SK' levelList.append('SK') elif selChap == '医疗重装': self.scheduleAdd['chap'] = 'A' levelList.append('PR-A') elif selChap == '术士狙击': self.scheduleAdd['chap'] = 'B' levelList.append('PR-B') elif selChap == '辅助先锋': self.scheduleAdd['chap'] = 'C' levelList.append('PR-C') elif selChap == '特种近卫': self.scheduleAdd['chap'] = 'D' levelList.append('PR-D') else: if selChap == '切尔诺伯格': self.scheduleAdd['chap'] = 'external' self.scheduleAdd['objLevel'] = 'ex1' elif selChap == '龙门外环': self.scheduleAdd['chap'] = 'external' self.scheduleAdd['objLevel'] = 'ex2' elif selChap == '龙门市区': self.scheduleAdd['chap'] = 'external' self.scheduleAdd['objLevel'] = 'ex3' elif selChap == '当期委托': self.scheduleAdd['chap'] = 'external' self.scheduleAdd['objLevel'] = 'ex4' self.level2Edit.clear() self.level2Edit.setReadOnly(True) self.level1Cb.addItems(levelList) def addLine(self): tempLevel = self.level2Edit.text() if 'EX' != self.scheduleAdd['part']: self.scheduleAdd['objLevel'] = '' tempTimes = self.timeEdit.text() self.scheduleAdd['times'] = '' if tempLevel != '': part1 = self.level1Cb.currentText() if part1 == 'LS': part1 = 'S' if tempLevel.isdecimal(): self.scheduleAdd['objLevel'] = part1 + '-' + tempLevel if tempTimes.isdecimal(): if self.isBootyMode: self.scheduleAdd['times'] = { 'bootyName': self.bootyName, 'bootyNum': tempTimes } else: self.scheduleAdd['times'] = tempTimes if self.scheduleAdd['objLevel'] != '' and self.scheduleAdd[ 'times'] != '': self.selList.append(self.scheduleAdd.copy()) self.refreshJsonView() def clickSchedule(self, qModelIndex): self.selIndex = qModelIndex.row() def delLine(self): if self.selIndex != None: self.listSchedule.pop(self.selIndex) self.selList.pop(self.selIndex) self.selIndex = None def moveUpLine(self): if self.selIndex != 0 and self.selIndex != None: #temp = self.listSchedule[self.selIndex - 1] self.listSchedule[self.selIndex - 1], self.listSchedule[self.selIndex] = \ self.listSchedule[self.selIndex], self.listSchedule[self.selIndex - 1] self.selList[self.selIndex - 1], self.selList[self.selIndex] = \ self.selList[self.selIndex], self.selList[self.selIndex - 1] self.selIndex = None def moveDownLine(self): if self.selIndex != (len(self.listSchedule) - 1) and self.selIndex != None: #temp = self.listSchedule[self.selIndex - 1] self.listSchedule[self.selIndex + 1], self.listSchedule[self.selIndex] = \ self.listSchedule[self.selIndex], self.listSchedule[self.selIndex + 1] self.selList[self.selIndex + 1], self.selList[self.selIndex] = \ self.selList[self.selIndex], self.selList[self.selIndex + 1] self.selIndex = None def editLine(self): if self.selIndex != None: if isinstance(self.selList[self.selIndex]['times'], dict): newNum, isOk = QInputDialog.getText(self, '修改', '请输入新的掉落物个数') if isOk: self.selList[self.selIndex]['times']['bootyNum'] = newNum else: newNum, isOk = QInputDialog.getText(self, '修改', '请输入新的次数') self.selList[self.selIndex]['times'] = newNum self.refreshJsonView() self.selIndex = None def clearLine(self): self.listSchedule.clear() self.selList.clear() def loadPlan(self): if self.planCb.currentIndex() != 0: self.jsonDict = self.jsonAll[self.planCb.currentIndex() + 1][ self.allPlanList[self.planCb.currentIndex()]] self.selList = self.jsonDict.copy() self.refreshJsonView() def addPlan(self): planName, ok = QInputDialog.getText(self, '配置名称', '请输入配置名称:') if ok: if '|' in planName: planName.replace('|', '·') self.allPlanList.append(planName) tempDict = dict() tempDict[planName] = self.selList.copy() self.jsonAll.append(tempDict) self.updateJson() self.planCb.clear() self.planCb.addItems(self.allPlanList) def delPlan(self): if self.planCb.currentIndex() != 0: self.allPlanList.pop(self.planCb.currentIndex()) self.jsonAll.pop(self.planCb.currentIndex() + 1) self.updateJson() self.planCb.clear() self.planCb.addItems(self.allPlanList) def setBootMode(self, isChecked): self.isBootyMode = isChecked if self.isBootyMode: self.timesLable.setText('个数:') self.bootySelBtn.setText('选择掉落物') else: self.timesLable.setText('次数:') self.bootySelBtn.setText('———') def test(self): self.listSchedule.append('add') print(self.listSchedule)
class DesktopIconWidget(QFrame): def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.Box | QFrame.Sunken) self.setStyleSheet("QListView{background:transparent;}") self.listView = QListView(self) self.setLayout(QHBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.listView) self.listView.setContextMenuPolicy(Qt.CustomContextMenu) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listView.setMovement(QListView.Snap) self.listView.setFlow(QListView.LeftToRight) self.listView.setResizeMode(QListView.Adjust) self.listView.setGridSize( QSize(self.logicalDpiX() / 96 * 70, self.logicalDpiY() / 96 * 70)) self.listView.setViewMode(QListView.IconMode) self.quickDesktopModel = QuickDesktopModel( self.window().platform.databaseFile) self.listView.setModel(self.quickDesktopModel) self.createActions() self.makeConnections() def createActions(self): self.actionCreateComputer = QAction(self.tr("我的电脑(&C)"), self) self.actionCreateDocuments = QAction(self.tr("我的文档(&D)"), self) self.actionCreateMusic = QAction(self.tr("我的音乐(&M)"), self) self.actionCreatePictures = QAction(self.tr("我的图片(&P)"), self) self.actionCreateShortcut = QAction(self.tr("创建快捷方式(&C)"), self) self.actionCreateShortcut.setIcon(QIcon(":/images/new.png")) self.actionCreateBookmark = QAction(self.tr("创建网络链接(&B)"), self) self.actionCreateBookmark.setIcon(QIcon(":/images/insert-link.png")) self.actionRemoveShortcut = QAction(self.tr("删除快捷方式(&R)"), self) self.actionRemoveShortcut.setIcon(QIcon(":/images/delete.png")) self.actionRenameShortcut = QAction(self.tr("重命名(&N)"), self) self.actionRenameShortcut.setIcon(QIcon(":/images/edit-rename.png")) self.actionEditShortcut = QAction(self.tr("编辑快捷方式(&E)"), self) self.actionEditShortcut.setIcon(QIcon(":/images/edit.png")) def makeConnections(self): self.listView.customContextMenuRequested.connect( self.onQuickDesktopContextMenuRequest) self.listView.activated.connect(self.runQuickDesktopShortcut) self.actionCreateComputer.triggered.connect( self.createComputerShortcut) self.actionCreateDocuments.triggered.connect( self.createDocumentsShortcut) self.actionCreateMusic.triggered.connect(self.createMusicShortcut) self.actionCreatePictures.triggered.connect( self.createPicturesShortcut) self.actionCreateShortcut.triggered.connect(self.createShortcut) self.actionCreateBookmark.triggered.connect(self.createBookmark) self.actionEditShortcut.triggered.connect(self.editShortcut) self.actionRemoveShortcut.triggered.connect(self.removeShortcut) self.actionRenameShortcut.triggered.connect(self.renameShortcut) def onQuickDesktopContextMenuRequest(self, pos): index = self.listView.indexAt(pos) self.listView.setCurrentIndex(index) menu = QMenu() menu.addAction(self.actionCreateShortcut) menu.addAction(self.actionCreateBookmark) menu2 = menu.addMenu(self.tr("创建特殊快捷方式(&S)")) if os.name == "nt": menu2.addAction(self.actionCreateComputer) menu2.addAction(self.actionCreateDocuments) menu2.addAction(self.actionCreatePictures) menu2.addAction(self.actionCreateMusic) if index.isValid(): menu.addAction(self.actionRemoveShortcut) if not self.quickDesktopModel.isSpecialShortcut(index): menu.addAction(self.actionEditShortcut) menu.addAction(self.actionRenameShortcut) try: getattr(menu, "exec")(QCursor.pos()) except AttributeError: getattr(menu, "exec_")(QCursor.pos()) def createShortcut(self): d = ShortcutDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = d.getResult() shortcut["id"] = str(uuid.uuid4()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createBookmark(self): d = BookmarkDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = { "id": str(uuid.uuid4()), "icon": "", "openwith": "", "dir": "", } shortcut.update(d.getResult()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createComputerShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的电脑"), "path": COMPUTER_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createDocumentsShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的文档"), "path": DOCUMENTS_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createPicturesShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("图片收藏"), "path": PICTURES_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createMusicShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的音乐"), "path": MUSIC_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def renameShortcut(self): self.listView.edit(self.listView.currentIndex()) def removeShortcut(self): self.quickDesktopModel.removeShortcut(self.listView.currentIndex()) def editShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return shortcut = self.quickDesktopModel.shortcutAt(index) url = QUrl.fromUserInput(shortcut["path"]) if not url.isValid(): return if url.scheme() == "special": QMessageBox.information(self, self.tr("编辑快捷方式"), self.tr("不能编辑特殊图标。")) return elif url.scheme() == "file": d = ShortcutDialog(self) else: d = BookmarkDialog(self) if self.window().runDialog(d.edit, shortcut) == QDialog.Accepted: shortcut.update(d.getResult()) self.quickDesktopModel.updateShortcut(shortcut, index) d.deleteLater() def runQuickDesktopShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return if not self.quickDesktopModel.runShortcut(index): QMessageBox.information(self, self.tr("快捷面板"), \ self.tr("不能运行快捷方式。请检查文件是否存在或者程序是否正确。")) else: self.window().close()
class MyApp(QWidget): is_resize = False is_rotate = False is_hfilp = False is_vfilp = False img_fomat = '(*.jpg , *.png , *.jpeg)' img_fomat_extension = ('.jpg', '.png', '.jpeg') file_paths = () rotate_data = 90 def __init__(self): super().__init__() self.initUI() def initUI(self): # Resize cb = QCheckBox('Resize', self) cb.stateChanged.connect(self.ischeckResize) self.le_width = QLineEdit(self) # resize img width self.le_width.setValidator(QIntValidator(0, 9999)) self.le_height = QLineEdit(self) # resize img height self.le_height.setValidator(QIntValidator(0, 9999)) #Rotate cb1 = QCheckBox('Rotate', self) cb1.stateChanged.connect(self.ischeckRotate) self.le_degree = QLineEdit(self) self.le_degree.setValidator(QIntValidator(1, 359)) self.le_degree.setText('90') #hflip cb2 = QCheckBox('hflip', self) cb2.stateChanged.connect(self.ischeckHfilp) #vflip cb3 = QCheckBox('vflip', self) cb3.stateChanged.connect(self.ischeckVfilp) #set path btn_path = QPushButton(self) btn_path.setText('set file path') btn_path.clicked.connect(self.setFilePath) btn_path_delete = QPushButton(self) btn_path_delete.setText('Delete file path') btn_path_delete.clicked.connect(self.deleteFilePath) self.listview = QListView(self) self.model = QStandardItemModel() #run btn_run = QPushButton(self) btn_run.setText('Run') btn_run.clicked.connect(self.file_change) btn_run.resize(100, 100) mainLayout = QGridLayout() mainLayout.setSizeConstraint(QLayout.SetFixedSize) #line 1 mainLayout.addWidget(cb, 0, 0, 1, 1) mainLayout.addWidget(self.le_width, 0, 1, 1, 1) mainLayout.addWidget(self.le_height, 0, 2, 1, 1) mainLayout.addWidget(btn_run, 0, 3, 1, 1) #line 2 mainLayout.addWidget(cb1, 1, 0, 1, 1) mainLayout.addWidget(self.le_degree, 1, 1, 1, 1) #line 3, 4 mainLayout.addWidget(cb2, 2, 0, 1, 1) mainLayout.addWidget(cb3, 3, 0, 1, 1) #line 5 mainLayout.addWidget(btn_path, 4, 1, 1, 1) mainLayout.addWidget(btn_path_delete, 4, 2, 1, 1) mainLayout.addWidget(self.listview, 5, 0, 4, 4) self.setLayout(mainLayout) self.setWindowTitle('ImageAug') self.show() def ischeckResize(self, state): if state == Qt.Checked: self.is_resize = True else: self.is_resize = False def ischeckRotate(self, state): if state == Qt.Checked: self.is_rotate = True else: self.is_rotate = False def ischeckHfilp(self, state): if state == Qt.Checked: self.is_hfilp = True else: self.is_hfilp = False def ischeckVfilp(self, state): if state == Qt.Checked: self.is_vfilp = True else: self.is_vfilp = False def setFilePath(self): #self.textEdit.setText('') fname = QFileDialog.getOpenFileNames(self, 'Open file', './', self.img_fomat) for a in fname[0]: #self.textEdit.setText(self.textEdit.toPlainText()+'\n'+a) self.model.appendRow(QStandardItem(a)) self.listview.setModel(self.model) def deleteFilePath(self): delete_item = self.listview.currentIndex().row() self.model.removeRow(delete_item) def file_change(self): if self.is_rotate: for i in range(self.model.rowCount()): path = self.model.index(i, 0, QModelIndex()).data(Qt.DisplayRole) self.setImgRotate(path) if self.is_resize: for i in range(self.model.rowCount()): path = self.model.index(i, 0, QModelIndex()).data(Qt.DisplayRole) self.setImgResize(path) if self.is_vfilp: for i in range(self.model.rowCount()): path = self.model.index(i, 0, QModelIndex()).data(Qt.DisplayRole) self.setImgFlip(path, 'v') if self.is_hfilp: for i in range(self.model.rowCount()): path = self.model.index(i, 0, QModelIndex()).data(Qt.DisplayRole) self.setImgFlip(path, 'h') def setImgResize(self, path): ## file name #print(path) name_idx = self.seach_filename(path) #print(path[name_idx : len(path)]) file_name = path[name_idx:len(path)] extension_idx = self.seach_extension(file_name) resize_file_name = file_name[0:extension_idx] \ + '_resize_' \ +file_name[extension_idx : len(file_name)] ## file resize img = Image.open(path) w = img.width h = img.height resize_width = int(self.le_width.text()) resize_height = int(self.le_height.text()) cvImage = np.ones((w, h, 3), np.uint8) * 255 cv2.cvtColor(cvImage, cv2.COLOR_BGR2RGB, cvImage) img_cv = cv2.imread(path) ## open cv read img file resizeImage = cv2.resize(img_cv, dsize=(resize_width, resize_height)) cv2.imwrite(path[0:name_idx] + resize_file_name, resizeImage) def setImgRotate(self, path): ## file name #print(path) degree = int(self.le_degree.text()) name_idx = self.seach_filename(path) #print(path[name_idx : len(path)]) file_name = path[name_idx:len(path)] extension_idx = self.seach_extension(file_name) rotate_file_name = file_name[0:extension_idx] \ + '_rotate_{}'.format(degree) \ +file_name[extension_idx : len(file_name)] ## file rotate img = Image.open(path) w = img.width h = img.height cvImage = np.ones((2 * w, 2 * h, 3), np.uint8) * 255 cv2.cvtColor(cvImage, cv2.COLOR_BGR2RGB, cvImage) img_cv = cv2.imread(path) ## open cv read img file # 2배의 이미지에 1/2이미지를 회전한다. resizeImage = cv2.resize(img_cv, dsize=(2 * w, 2 * h)) # img size X 2 M = cv2.getRotationMatrix2D((w, h), degree, 0.5) # 0.5 scale rotate rotated = cv2.warpAffine(resizeImage, M, (2 * w, 2 * h)) # 배경 이미지를 줄이기 위해 좌표 계산후 이미지를 자른다. x_min, x_max, y_min, y_max = self.rotate_xy_min_max(w, h, degree) rotated2 = rotated[y_min:y_max, x_min:x_max] # img cut cv2.imwrite(path[0:name_idx] + rotate_file_name, rotated2) def setImgFlip(self, path, mode): ## file name #print(path) name_idx = self.seach_filename(path) #print(path[name_idx : len(path)]) file_name = path[name_idx:len(path)] extension_idx = self.seach_extension(file_name) resize_file_name = file_name[0:extension_idx] \ + '_{}flip_'.format(mode) \ +file_name[extension_idx : len(file_name)] ## file flip img = Image.open(path) w = img.width h = img.height cvImage = np.ones((w, h, 3), np.uint8) * 255 cv2.cvtColor(cvImage, cv2.COLOR_BGR2RGB, cvImage) img_cv = cv2.imread(path) ## open cv read img file if 'v' in mode: flipImage = cv2.flip(img_cv, 1) elif 'h' in mode: flipImage = cv2.flip(img_cv, 0) cv2.imwrite(path[0:name_idx] + resize_file_name, flipImage) def seach_filename(self, path): str = path result = 0 while True: idx = str.find('/') if idx > -1: #print(idx) str = str[idx + 1:len(str)] result += idx + 1 else: break return result def seach_extension(self, name): for extension in self.img_fomat_extension: extension_idx = name.find(extension) if extension_idx > -1: return extension_idx def rotate_xy_min_max(self, w, h, degrees): th = math.radians(degrees) sin = math.sin(th) cos = math.cos(th) x1 = (w / 2 * 3 - w) * cos - (h / 2 - h) * sin + w x2 = (w / 2 - w) * cos - (h / 2 - h) * sin + w x3 = (w / 2 - w) * cos - (h / 2 * 3 - h) * sin + w x4 = (w / 2 * 3 - w) * cos - (h / 2 * 3 - h) * sin + w y1 = (w / 2 * 3 - w) * sin + (h / 2 - h) * cos + h y2 = (w / 2 - w) * sin + (h / 2 - h) * cos + h y3 = (w / 2 - w) * sin + (h / 2 * 3 - h) * cos + h y4 = (w / 2 * 3 - w) * sin + (h / 2 * 3 - h) * cos + h x_min = 99999 x_max = 0 y_min = 99999 y_max = 0 x_range = (x1, x2, x3, x4) y_range = (y1, y2, y3, y4) for i in range(4): if x_max < x_range[i]: x_max = x_range[i] if x_range[i] < x_min: x_min = x_range[i] if y_max < y_range[i]: y_max = y_range[i] if y_range[i] < y_min: y_min = y_range[i] ''' print('{} , {} '.format(w,h)) print(' {} , {} , {} , {} '.format(x_range[0] , x_range[1], x_range[2], x_range[3])) print(' {} , {} , {} , {} '.format(y_range[0] , y_range[1], y_range[2], y_range[3])) print(' {} , {} , {} , {} '.format(int(x_min) , int(x_max) , int(y_min) , int(y_max))) print(' {} , {} , {} , {} '.format(x1,x2,x3,x4)) print(' {} , {} , {} , {} '.format(y1, y2, y3, y4)) ''' return int(x_min), int(x_max), int(y_min), int(y_max)
class MyApp(Data): def __init__(self): super().__init__() # setting tabs self.tab1 = QGroupBox() self.tab2 = QGroupBox() self.tab3 = QGroupBox() self.tabs = QTabWidget() self.stack = QStackedWidget(self) # tab3 setting self.btn_show = QPushButton("show") self.tab3_group_11 = QVBoxLayout() self.tab3_group_22 = QVBoxLayout() self.stack2 = QStackedWidget(self) self.week = ("mon", "tue", "wed", "thu", "fri") self.classes_input = [ ] # input text from first tab 'lineEdit' to next tab 'btns_name' self.btns_name = [ ] # QRadioButton, set by the classes_input with next push button self.btns_week = [] # QRadioButton for week on second window self.btn_set = QPushButton("SET") # SET 버튼 누를 때마다 데이터 저장 self.initUI() # def initUI(self): # # tab1 레이아웃 설정 self.Tab1() # tab1 레이아웃 설정 반영 # # # stack 에 요일들 추가 self.set_stack() # # tab2 레이아웃 설정 self.Tab2() # tab2 레이아웃 설정 반영 # # # tab3 레이아웃 설정 self.Tab3() # tab3 레이아웃 설정 반영 # self.tabs.addTab(self.tab1, "수업 이름 설정") self.tabs.addTab(self.tab2, "수업 시간들 추가") self.tabs.addTab(self.tab3, "시간표") # tab3 추가 vbox = QVBoxLayout() vbox.addWidget(self.tabs) self.setLayout(vbox) self.setWindowTitle('Timetable Maker') lotus = QIcon(self.resource_path('./assets/lotus.ico')) self.setWindowIcon(lotus) self.setGeometry(1200, 500, 500, 500) self.show() def next1_clicked(self): for i in range(10): self.btns_name[i].setText(self.classes_input[i].text()) self.tabs.setCurrentIndex(1) def Tab1(self): # setting for tab1 layout_1 = QGridLayout() for i in range(10): layout_1.addWidget(QLabel("Class %d." % (i + 1)), i, 0) for i in range(10): self.classes_input.append(QLineEdit()) for i in range(10): layout_1.addWidget(self.classes_input[i], i, 1) btn_next = QPushButton("&next") layout_1.addWidget(btn_next, 11, 2) btn_next.clicked.connect(self.next1_clicked) self.tabs.tabBarClicked.connect(self.next1_clicked) self.tab1.setLayout(layout_1) def Tab2(self): # setting for tab2 layout_2 = QGridLayout() # 1. class 이름 목록 group_1 = QGroupBox("class") group_11 = QVBoxLayout() for i in range(10): self.btns_name.append(QRadioButton()) group_11.addWidget(self.btns_name[i]) # lineEdit 과 connect 하기 self.btns_name[i].clicked.connect(self.class_name_clicked) group_1.setLayout(group_11) # class 이름 목록 설정 완료 # 2. week 목록 week = ("mon", "tue", "wed", "thu", "fri") group_2 = QGroupBox("week") group_22 = QVBoxLayout() for i in range(5): self.btns_week.append(QRadioButton(week[i])) group_22.addWidget(self.btns_week[i]) self.btns_week[i].clicked.connect(self.week_changed) group_2.setLayout(group_22) layout_2.addWidget(group_1, 0, 0) layout_2.addWidget(group_2, 0, 1) layout_2.addWidget(self.stack, 0, 2) btn_set = QPushButton("SET") btn_set.setStyleSheet( "color: red; selection-color: yellow; background-color: yellow; font: bold 14px" ) layout_2.addWidget(btn_set, 1, 2) btn_set.clicked.connect(self.set_clicked) self.tab2.setLayout(layout_2) def class_name_clicked(self): for t in range(50): self.unify_time[t].setChecked(False) self.set_color_blue() def Tab3(self): # tab3 outfit layout_3 = QGridLayout() group_1 = QGroupBox("Options") group_1.setLayout(self.tab3_group_11) layout_3.addWidget(group_1, 0, 0, 1, 1) group_1.setMaximumSize(400, 2000) group_2 = QGroupBox("Table") group_2.setLayout(self.tab3_group_22) layout_3.addWidget(self.stack2, 0, 1, 1, 3) save = QPushButton("SAVE") info = QPushButton("info") self.btn_show.clicked.connect(self.btn_show_clicked) save.clicked.connect(self.save_clicked) info.clicked.connect(self.info_clicked) layout_3.addWidget(self.btn_show, 1, 0) layout_3.addWidget(save, 1, 3) layout_3.addWidget(info, 1, 2) self.tab3.setLayout(layout_3) def save_clicked(self): view_index = self.view.currentIndex() index = view_index.row() text_write = [] class_info = "" for i, j in enumerate(self.table_making.class_seq[index]): temp_dialog_message = "" for k in self.sets_list[i][j]: temp_num_week = int(k) // 10 temp_num_time = int(k) % 10 temp_dialog_message += f"{self.week[temp_num_week]}_{temp_num_time + 1}, " class_info += "{0} ---> {1} \n".format( str(self.classes_input[i].text()), temp_dialog_message) indexed_table_list = self.table_making.lines[index * 11:index * 11 + 11] for line in indexed_table_list: text_write.append(str(line) + '\n') with open(f"..\\option{index + 1}.txt", 'w') as f: for one_line in text_write: f.write(one_line) f.write('\n') f.write(class_info) f.write('\n') f.write("(set font to 'D2CODING' or any monospaced font)") def tab3_show(self): self.view = QListView(self) self.model = QStandardItemModel() option_length = len(self.table_making.class_set) for option in range(option_length): self.model.appendRow(QStandardItem("option%d" % (option + 1))) table = QGroupBox("table%d" % (option + 1)) table_box = QVBoxLayout() for i in self.table_making.lines[option * 11:(option * 11 + 11)]: label = QLabel(i, self) label.setFont(QFont('D2Coding Bold')) table_box.addWidget(label) table.setLayout(table_box) self.stack2.addWidget(table) self.view.setModel(self.model) self.tab3_group_11.addWidget(self.view) self.view.clicked.connect(self.slot_clicked_item) def slot_clicked_item(self, index): self.stack2.setCurrentIndex(index.row()) def info_clicked(self): view_index = self.view.currentIndex() index = view_index.row() title = "option%d" % (index + 1) message = "" for i, j in enumerate(self.table_making.class_seq[index]): temp_dialog_message = "" for k in self.sets_list[i][j]: temp_num_week = int(k) // 10 temp_num_time = int(k) % 10 temp_dialog_message += f"{self.week[temp_num_week]}_{temp_num_time + 1}, " message += "{0} ---> {1} \n".format( str(self.classes_input[i].text()), temp_dialog_message) QMessageBox.information(self, title, message) def resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath('.'), relative_path)
class comics_project_manager_docker(DockWidget): setupDictionary = {} stringName = i18n("Comics Manager") projecturl = None def __init__(self): super().__init__() self.setWindowTitle(self.stringName) # Setup layout: base = QHBoxLayout() widget = QWidget() widget.setLayout(base) baseLayout = QSplitter() base.addWidget(baseLayout) self.setWidget(widget) buttonLayout = QVBoxLayout() buttonBox = QWidget() buttonBox.setLayout(buttonLayout) baseLayout.addWidget(buttonBox) # Comic page list and pages model self.comicPageList = QListView() self.comicPageList.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.comicPageList.setDragEnabled(True) self.comicPageList.setDragDropMode(QAbstractItemView.InternalMove) self.comicPageList.setDefaultDropAction(Qt.MoveAction) self.comicPageList.setAcceptDrops(True) self.comicPageList.setItemDelegate(comic_page_delegate()) self.pagesModel = QStandardItemModel() self.comicPageList.doubleClicked.connect(self.slot_open_page) self.comicPageList.setIconSize(QSize(128, 128)) # self.comicPageList.itemDelegate().closeEditor.connect(self.slot_write_description) self.pagesModel.layoutChanged.connect(self.slot_write_config) self.pagesModel.rowsInserted.connect(self.slot_write_config) self.pagesModel.rowsRemoved.connect(self.slot_write_config) self.pagesModel.rowsMoved.connect(self.slot_write_config) self.comicPageList.setModel(self.pagesModel) pageBox = QWidget() pageBox.setLayout(QVBoxLayout()) zoomSlider = QSlider(Qt.Horizontal, None) zoomSlider.setRange(1, 8) zoomSlider.setValue(4) zoomSlider.setTickInterval(1) zoomSlider.setMinimumWidth(10) zoomSlider.valueChanged.connect(self.slot_scale_thumbnails) self.projectName = Elided_Text_Label() pageBox.layout().addWidget(self.projectName) pageBox.layout().addWidget(zoomSlider) pageBox.layout().addWidget(self.comicPageList) baseLayout.addWidget(pageBox) self.btn_project = QToolButton() self.btn_project.setPopupMode(QToolButton.MenuButtonPopup) self.btn_project.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) menu_project = QMenu() self.action_new_project = QAction(i18n("New Project"), self) self.action_new_project.triggered.connect(self.slot_new_project) self.action_load_project = QAction(i18n("Open Project"), self) self.action_load_project.triggered.connect(self.slot_open_config) menu_project.addAction(self.action_new_project) menu_project.addAction(self.action_load_project) self.btn_project.setMenu(menu_project) self.btn_project.setDefaultAction(self.action_load_project) buttonLayout.addWidget(self.btn_project) # Settings dropdown with actions for the different settings menus. self.btn_settings = QToolButton() self.btn_settings.setPopupMode(QToolButton.MenuButtonPopup) self.btn_settings.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.action_edit_project_settings = QAction(i18n("Project Settings"), self) self.action_edit_project_settings.triggered.connect( self.slot_edit_project_settings) self.action_edit_meta_data = QAction(i18n("Meta Data"), self) self.action_edit_meta_data.triggered.connect(self.slot_edit_meta_data) self.action_edit_export_settings = QAction(i18n("Export Settings"), self) self.action_edit_export_settings.triggered.connect( self.slot_edit_export_settings) menu_settings = QMenu() menu_settings.addAction(self.action_edit_project_settings) menu_settings.addAction(self.action_edit_meta_data) menu_settings.addAction(self.action_edit_export_settings) self.btn_settings.setDefaultAction(self.action_edit_project_settings) self.btn_settings.setMenu(menu_settings) buttonLayout.addWidget(self.btn_settings) self.btn_settings.setDisabled(True) # Add page drop down with different page actions. self.btn_add_page = QToolButton() self.btn_add_page.setPopupMode(QToolButton.MenuButtonPopup) self.btn_add_page.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum) self.action_add_page = QAction(i18n("Add Page"), self) self.action_add_page.triggered.connect(self.slot_add_new_page_single) self.action_add_template = QAction(i18n("Add Page from Template"), self) self.action_add_template.triggered.connect( self.slot_add_new_page_from_template) self.action_add_existing = QAction(i18n("Add Existing Pages"), self) self.action_add_existing.triggered.connect(self.slot_add_page_from_url) self.action_remove_selected_page = QAction(i18n("Remove Page"), self) self.action_remove_selected_page.triggered.connect( self.slot_remove_selected_page) self.action_resize_all_pages = QAction(i18n("Batch Resize"), self) self.action_resize_all_pages.triggered.connect(self.slot_batch_resize) self.btn_add_page.setDefaultAction(self.action_add_page) self.action_show_page_viewer = QAction(i18n("View Page In Window"), self) self.action_show_page_viewer.triggered.connect( self.slot_show_page_viewer) self.action_scrape_authors = QAction(i18n("Scrape Author Info"), self) self.action_scrape_authors.setToolTip( i18n( "Search for author information in documents and add it to the author list. This does not check for duplicates." )) self.action_scrape_authors.triggered.connect( self.slot_scrape_author_list) self.action_scrape_translations = QAction( i18n("Scrape Text for Translation"), self) self.action_scrape_translations.triggered.connect( self.slot_scrape_translations) actionList = [] menu_page = QMenu() actionList.append(self.action_add_page) actionList.append(self.action_add_template) actionList.append(self.action_add_existing) actionList.append(self.action_remove_selected_page) actionList.append(self.action_resize_all_pages) actionList.append(self.action_show_page_viewer) actionList.append(self.action_scrape_authors) actionList.append(self.action_scrape_translations) menu_page.addActions(actionList) self.btn_add_page.setMenu(menu_page) buttonLayout.addWidget(self.btn_add_page) self.btn_add_page.setDisabled(True) self.comicPageList.setContextMenuPolicy(Qt.ActionsContextMenu) self.comicPageList.addActions(actionList) # Export button that... exports. self.btn_export = QPushButton(i18n("Export Comic")) self.btn_export.clicked.connect(self.slot_export) buttonLayout.addWidget(self.btn_export) self.btn_export.setDisabled(True) self.btn_project_url = QPushButton(i18n("Copy Location")) self.btn_project_url.setToolTip( i18n( "Copies the path of the project to the clipboard. Useful for quickly copying to a file manager or the like." )) self.btn_project_url.clicked.connect(self.slot_copy_project_url) self.btn_project_url.setDisabled(True) buttonLayout.addWidget(self.btn_project_url) self.page_viewer_dialog = comics_project_page_viewer.comics_project_page_viewer( ) Application.notifier().imageSaved.connect( self.slot_check_for_page_update) buttonLayout.addItem( QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.MinimumExpanding)) """ Open the config file and load the json file into a dictionary. """ def slot_open_config(self): self.path_to_config = QFileDialog.getOpenFileName( caption=i18n("Please select the JSON comic config file."), filter=str(i18n("JSON files") + "(*.json)"))[0] if os.path.exists(self.path_to_config) is True: configFile = open(self.path_to_config, "r", newline="", encoding="utf-16") self.setupDictionary = json.load(configFile) self.projecturl = os.path.dirname(str(self.path_to_config)) configFile.close() self.load_config() """ Further config loading. """ def load_config(self): self.projectName.setMainText( text=str(self.setupDictionary["projectName"])) self.fill_pages() self.btn_settings.setEnabled(True) self.btn_add_page.setEnabled(True) self.btn_export.setEnabled(True) self.btn_project_url.setEnabled(True) """ Fill the pages model with the pages from the pages list. """ def fill_pages(self): self.loadingPages = True self.pagesModel.clear() pagesList = [] if "pages" in self.setupDictionary.keys(): pagesList = self.setupDictionary["pages"] progress = QProgressDialog() progress.setMinimum(0) progress.setMaximum(len(pagesList)) progress.setWindowTitle(i18n("Loading Pages...")) for url in pagesList: absurl = os.path.join(self.projecturl, url) if (os.path.exists(absurl)): #page = Application.openDocument(absurl) page = zipfile.ZipFile(absurl, "r") thumbnail = QImage.fromData(page.read("preview.png")) pageItem = QStandardItem() dataList = self.get_description_and_title( page.read("documentinfo.xml")) if (dataList[0].isspace() or len(dataList[0]) < 1): dataList[0] = os.path.basename(url) pageItem.setText(dataList[0].replace("_", " ")) pageItem.setDragEnabled(True) pageItem.setDropEnabled(False) pageItem.setEditable(False) pageItem.setIcon(QIcon(QPixmap.fromImage(thumbnail))) pageItem.setData(dataList[1], role=CPE.DESCRIPTION) pageItem.setData(url, role=CPE.URL) pageItem.setData(dataList[2], role=CPE.KEYWORDS) pageItem.setData(dataList[3], role=CPE.LASTEDIT) pageItem.setData(dataList[4], role=CPE.EDITOR) pageItem.setToolTip(url) page.close() self.pagesModel.appendRow(pageItem) progress.setValue(progress.value() + 1) progress.setValue(len(pagesList)) self.loadingPages = False """ Function that is triggered by the zoomSlider Resizes the thumbnails. """ def slot_scale_thumbnails(self, multiplier=4): self.comicPageList.setIconSize(QSize(multiplier * 32, multiplier * 32)) """ Function that takes the documentinfo.xml and parses it for the title, subject and abstract tags, to get the title and description. @returns a stringlist with the name on 0 and the description on 1. """ def get_description_and_title(self, string): xmlDoc = ET.fromstring(string) calligra = str("{http://www.calligra.org/DTD/document-info}") name = "" if ET.iselement(xmlDoc[0].find(calligra + 'title')): name = xmlDoc[0].find(calligra + 'title').text if name is None: name = " " desc = "" if ET.iselement(xmlDoc[0].find(calligra + 'subject')): desc = xmlDoc[0].find(calligra + 'subject').text if desc is None or desc.isspace() or len(desc) < 1: if ET.iselement(xmlDoc[0].find(calligra + 'abstract')): desc = xmlDoc[0].find(calligra + 'abstract').text if desc is not None: if desc.startswith("<![CDATA["): desc = desc[len("<![CDATA["):] if desc.startswith("]]>"): desc = desc[:-len("]]>")] keywords = "" if ET.iselement(xmlDoc[0].find(calligra + 'keyword')): keywords = xmlDoc[0].find(calligra + 'keyword').text date = "" if ET.iselement(xmlDoc[0].find(calligra + 'date')): date = xmlDoc[0].find(calligra + 'date').text author = [] if ET.iselement(xmlDoc[1].find(calligra + 'creator-first-name')): string = xmlDoc[1].find(calligra + 'creator-first-name').text if string is not None: author.append(string) if ET.iselement(xmlDoc[1].find(calligra + 'creator-last-name')): string = xmlDoc[1].find(calligra + 'creator-last-name').text if string is not None: author.append(string) if ET.iselement(xmlDoc[1].find(calligra + 'full-name')): string = xmlDoc[1].find(calligra + 'full-name').text if string is not None: author.append(string) return [name, desc, keywords, date, " ".join(author)] """ Scrapes authors from the author data in the document info and puts them into the author list. Doesn't check for duplicates. """ def slot_scrape_author_list(self): listOfAuthors = [] if "authorList" in self.setupDictionary.keys(): listOfAuthors = self.setupDictionary["authorList"] if "pages" in self.setupDictionary.keys(): for relurl in self.setupDictionary["pages"]: absurl = os.path.join(self.projecturl, relurl) page = zipfile.ZipFile(absurl, "r") xmlDoc = ET.fromstring(page.read("documentinfo.xml")) calligra = str("{http://www.calligra.org/DTD/document-info}") authorelem = xmlDoc.find(calligra + 'author') author = {} if ET.iselement(authorelem.find(calligra + 'full-name')): author["nickname"] = str( authorelem.find(calligra + 'full-name').text) if ET.iselement( authorelem.find(calligra + 'creator-first-name')): author["first-name"] = str( authorelem.find(calligra + 'creator-first-name').text) if ET.iselement(authorelem.find(calligra + 'initial')): author["initials"] = str( authorelem.find(calligra + 'initial').text) if ET.iselement(authorelem.find(calligra + 'creator-last-name')): author["last-name"] = str( authorelem.find(calligra + 'creator-last-name').text) if ET.iselement(authorelem.find(calligra + 'email')): author["email"] = str( authorelem.find(calligra + 'email').text) if ET.iselement(authorelem.find(calligra + 'contact')): contact = authorelem.find(calligra + 'contact') contactMode = contact.get("type") if contactMode == "email": author["email"] = str(contact.text) if contactMode == "homepage": author["homepage"] = str(contact.text) if ET.iselement(authorelem.find(calligra + 'position')): author["role"] = str( authorelem.find(calligra + 'position').text) listOfAuthors.append(author) page.close() self.setupDictionary["authorList"] = listOfAuthors """ Edit the general project settings like the project name, concept, pages location, export location, template location, metadata """ def slot_edit_project_settings(self): dialog = comics_project_settings_dialog.comics_project_details_editor( self.projecturl) dialog.setConfig(self.setupDictionary, self.projecturl) if dialog.exec_() == QDialog.Accepted: self.setupDictionary = dialog.getConfig(self.setupDictionary) self.slot_write_config() self.projectName.setMainText( str(self.setupDictionary["projectName"])) """ This allows users to select existing pages and add them to the pages list. The pages are currently not copied to the pages folder. Useful for existing projects. """ def slot_add_page_from_url(self): # get the pages. urlList = QFileDialog.getOpenFileNames( caption=i18n("Which existing pages to add?"), directory=self.projecturl, filter=str(i18n("Krita files") + "(*.kra)"))[0] # get the existing pages list. pagesList = [] if "pages" in self.setupDictionary.keys(): pagesList = self.setupDictionary["pages"] # And add each url in the url list to the pages list and the model. for url in urlList: if self.projecturl not in urlList: newUrl = os.path.join(self.projecturl, self.setupDictionary["pagesLocation"], os.path.basename(url)) shutil.move(url, newUrl) url = newUrl relative = os.path.relpath(url, self.projecturl) if url not in pagesList: page = zipfile.ZipFile(url, "r") thumbnail = QImage.fromData(page.read("preview.png")) dataList = self.get_description_and_title( page.read("documentinfo.xml")) if (dataList[0].isspace() or len(dataList[0]) < 1): dataList[0] = os.path.basename(url) newPageItem = QStandardItem() newPageItem.setIcon(QIcon(QPixmap.fromImage(thumbnail))) newPageItem.setDragEnabled(True) newPageItem.setDropEnabled(False) newPageItem.setEditable(False) newPageItem.setText(dataList[0].replace("_", " ")) newPageItem.setData(dataList[1], role=CPE.DESCRIPTION) newPageItem.setData(relative, role=CPE.URL) newPageItem.setData(dataList[2], role=CPE.KEYWORDS) newPageItem.setData(dataList[3], role=CPE.LASTEDIT) newPageItem.setData(dataList[4], role=CPE.EDITOR) newPageItem.setToolTip(relative) page.close() self.pagesModel.appendRow(newPageItem) """ Remove the selected page from the list of pages. This does not remove it from disk(far too dangerous). """ def slot_remove_selected_page(self): index = self.comicPageList.currentIndex() self.pagesModel.removeRow(index.row()) """ This function adds a new page from the default template. If there's no default template, or the file does not exist, it will show the create/import template dialog. It will remember the selected item as the default template. """ def slot_add_new_page_single(self): templateUrl = "templatepage" templateExists = False if "singlePageTemplate" in self.setupDictionary.keys(): templateUrl = self.setupDictionary["singlePageTemplate"] if os.path.exists(os.path.join(self.projecturl, templateUrl)): templateExists = True if templateExists is False: if "templateLocation" not in self.setupDictionary.keys(): self.setupDictionary["templateLocation"] = os.path.relpath( QFileDialog.getExistingDirectory( caption=i18n("Where are the templates located?"), options=QFileDialog.ShowDirsOnly), self.projecturl) templateDir = os.path.join( self.projecturl, self.setupDictionary["templateLocation"]) template = comics_template_dialog.comics_template_dialog( templateDir) if template.exec_() == QDialog.Accepted: templateUrl = os.path.relpath(template.url(), self.projecturl) self.setupDictionary["singlePageTemplate"] = templateUrl if os.path.exists(os.path.join(self.projecturl, templateUrl)): self.add_new_page(templateUrl) """ This function always asks for a template showing the new template window. This allows users to have multiple different templates created for back covers, spreads, other and have them accessible, while still having the convenience of a singular "add page" that adds a default. """ def slot_add_new_page_from_template(self): if "templateLocation" not in self.setupDictionary.keys(): self.setupDictionary["templateLocation"] = os.path.relpath( QFileDialog.getExistingDirectory( caption=i18n("Where are the templates located?"), options=QFileDialog.ShowDirsOnly), self.projecturl) templateDir = os.path.join(self.projecturl, self.setupDictionary["templateLocation"]) template = comics_template_dialog.comics_template_dialog(templateDir) if template.exec_() == QDialog.Accepted: templateUrl = os.path.relpath(template.url(), self.projecturl) self.add_new_page(templateUrl) """ This is the actual function that adds the template using the template url. It will attempt to name the new page projectName+number. """ def add_new_page(self, templateUrl): # check for page list and or location. pagesList = [] if "pages" in self.setupDictionary.keys(): pagesList = self.setupDictionary["pages"] if not "pageNumber" in self.setupDictionary.keys(): self.setupDictionary['pageNumber'] = 0 if (str(self.setupDictionary["pagesLocation"]).isspace()): self.setupDictionary["pagesLocation"] = os.path.relpath( QFileDialog.getExistingDirectory( caption=i18n("Where should the pages go?"), options=QFileDialog.ShowDirsOnly), self.projecturl) # Search for the possible name. extraUnderscore = str() if str(self.setupDictionary["projectName"])[-1].isdigit(): extraUnderscore = "_" self.setupDictionary['pageNumber'] += 1 pageName = str(self.setupDictionary["projectName"]).replace( " ", "_") + extraUnderscore + str( format(self.setupDictionary['pageNumber'], "03d")) url = os.path.join(str(self.setupDictionary["pagesLocation"]), pageName + ".kra") # open the page by opening the template and resaving it, or just opening it. absoluteUrl = os.path.join(self.projecturl, url) if (os.path.exists(absoluteUrl)): newPage = Application.openDocument(absoluteUrl) else: booltemplateExists = os.path.exists( os.path.join(self.projecturl, templateUrl)) if booltemplateExists is False: templateUrl = os.path.relpath( QFileDialog.getOpenFileName( caption=i18n( "Which image should be the basis the new page?"), directory=self.projecturl, filter=str(i18n("Krita files") + "(*.kra)"))[0], self.projecturl) newPage = Application.openDocument( os.path.join(self.projecturl, templateUrl)) newPage.waitForDone() newPage.setFileName(absoluteUrl) newPage.setName(pageName.replace("_", " ")) newPage.save() newPage.waitForDone() # Get out the extra data for the standard item. newPageItem = QStandardItem() newPageItem.setIcon( QIcon(QPixmap.fromImage(newPage.thumbnail(256, 256)))) newPageItem.setDragEnabled(True) newPageItem.setDropEnabled(False) newPageItem.setEditable(False) newPageItem.setText(pageName.replace("_", " ")) newPageItem.setData("", role=CPE.DESCRIPTION) newPageItem.setData(url, role=CPE.URL) newPageItem.setData("", role=CPE.KEYWORDS) newPageItem.setData("", role=CPE.LASTEDIT) newPageItem.setData("", role=CPE.EDITOR) newPageItem.setToolTip(url) # close page document. while os.path.exists(absoluteUrl) is False: qApp.processEvents() newPage.close() # add item to page. self.pagesModel.appendRow(newPageItem) """ Write to the json configuration file. This also checks the current state of the pages list. """ def slot_write_config(self): # Don't load when the pages are still being loaded, otherwise we'll be overwriting our own pages list. if (self.loadingPages is False): print("CPMT: writing comic configuration...") # Generate a pages list from the pagesmodel. pagesList = [] for i in range(self.pagesModel.rowCount()): index = self.pagesModel.index(i, 0) url = str(self.pagesModel.data(index, role=CPE.URL)) if url not in pagesList: pagesList.append(url) self.setupDictionary["pages"] = pagesList # Save to our json file. configFile = open(self.path_to_config, "w", newline="", encoding="utf-16") json.dump(self.setupDictionary, configFile, indent=4, sort_keys=True, ensure_ascii=False) configFile.close() print("CPMT: done") """ Open a page in the pagesmodel in Krita. """ def slot_open_page(self, index): if index.column() is 0: # Get the absolute url from the relative one in the pages model. absoluteUrl = os.path.join( self.projecturl, str(self.pagesModel.data(index, role=CPE.URL))) # Make sure the page exists. if os.path.exists(absoluteUrl): page = Application.openDocument(absoluteUrl) # Set the title to the filename if it was empty. It looks a bit neater. if page.name().isspace or len(page.name()) < 1: page.setName( str(self.pagesModel.data(index, role=Qt.DisplayRole)).replace( "_", " ")) # Add views for the document so the user can use it. Application.activeWindow().addView(page) Application.setActiveDocument(page) else: print( "CPMT: The page cannot be opened because the file doesn't exist:", absoluteUrl) """ Call up the metadata editor dialog. Only when the dialog is "Accepted" will the metadata be saved. """ def slot_edit_meta_data(self): dialog = comics_metadata_dialog.comic_meta_data_editor() dialog.setConfig(self.setupDictionary) if (dialog.exec_() == QDialog.Accepted): self.setupDictionary = dialog.getConfig(self.setupDictionary) self.slot_write_config() """ An attempt at making the description editable from the comic pages list. It is currently not working because ZipFile has no overwrite mechanism, and I don't have the energy to write one yet. """ def slot_write_description(self, index): for row in range(self.pagesModel.rowCount()): index = self.pagesModel.index(row, 1) indexUrl = self.pagesModel.index(row, 0) absoluteUrl = os.path.join( self.projecturl, str(self.pagesModel.data(indexUrl, role=CPE.URL))) page = zipfile.ZipFile(absoluteUrl, "a") xmlDoc = ET.ElementTree() ET.register_namespace("", "http://www.calligra.org/DTD/document-info") location = os.path.join(self.projecturl, "documentinfo.xml") xmlDoc.parse(location) xmlroot = ET.fromstring(page.read("documentinfo.xml")) calligra = "{http://www.calligra.org/DTD/document-info}" aboutelem = xmlroot.find(calligra + 'about') if ET.iselement(aboutelem.find(calligra + 'subject')): desc = aboutelem.find(calligra + 'subject') desc.text = self.pagesModel.data(index, role=Qt.EditRole) xmlstring = ET.tostring(xmlroot, encoding='unicode', method='xml', short_empty_elements=False) page.writestr(zinfo_or_arcname="documentinfo.xml", data=xmlstring) for document in Application.documents(): if str(document.fileName()) == str(absoluteUrl): document.setDocumentInfo(xmlstring) page.close() """ Calls up the export settings dialog. Only when accepted will the configuration be written. """ def slot_edit_export_settings(self): dialog = comics_export_dialog.comic_export_setting_dialog() dialog.setConfig(self.setupDictionary) if (dialog.exec_() == QDialog.Accepted): self.setupDictionary = dialog.getConfig(self.setupDictionary) self.slot_write_config() """ Export the comic. Won't work without export settings set. """ def slot_export(self): #ensure there is a unique identifier if "uuid" not in self.setupDictionary.keys(): uuid = str() if "acbfID" in self.setupDictionary.keys(): uuid = str(self.setupDictionary["acbfID"]) else: uuid = QUuid.createUuid().toString() self.setupDictionary["uuid"] = uuid exporter = comics_exporter.comicsExporter() exporter.set_config(self.setupDictionary, self.projecturl) exportSuccess = exporter.export() if exportSuccess: print( "CPMT: Export success! The files have been written to the export folder!" ) QMessageBox.information( self, i18n("Export success"), i18n("The files have been written to the export folder."), QMessageBox.Ok) """ Calls up the comics project setup wizard so users can create a new json file with the basic information. """ def slot_new_project(self): setup = comics_project_setup_wizard.ComicsProjectSetupWizard() setup.showDialog() """ This is triggered by any document save. It checks if the given url in in the pages list, and if so, updates the appropriate page thumbnail. This helps with the management of the pages, because the user will be able to see the thumbnails as a todo for the whole comic, giving a good overview over whether they still need to ink, color or the like for a given page, and it thus also rewards the user whenever they save. """ def slot_check_for_page_update(self, url): if "pages" in self.setupDictionary.keys(): relUrl = os.path.relpath(url, self.projecturl) if relUrl in self.setupDictionary["pages"]: index = self.pagesModel.index( self.setupDictionary["pages"].index(relUrl), 0) if index.isValid(): pageItem = self.pagesModel.itemFromIndex(index) page = zipfile.ZipFile(url, "r") dataList = self.get_description_and_title( page.read("documentinfo.xml")) if (dataList[0].isspace() or len(dataList[0]) < 1): dataList[0] = os.path.basename(url) thumbnail = QImage.fromData(page.read("preview.png")) pageItem.setIcon(QIcon(QPixmap.fromImage(thumbnail))) pageItem.setText(dataList[0]) pageItem.setData(dataList[1], role=CPE.DESCRIPTION) pageItem.setData(url, role=CPE.URL) pageItem.setData(dataList[2], role=CPE.KEYWORDS) pageItem.setData(dataList[3], role=CPE.LASTEDIT) pageItem.setData(dataList[4], role=CPE.EDITOR) self.pagesModel.setItem(index.row(), index.column(), pageItem) """ Resize all the pages in the pages list. It will show a dialog with the options for resizing. Then, it will try to pop up a progress dialog while resizing. The progress dialog shows the remaining time and pages. """ def slot_batch_resize(self): dialog = QDialog() dialog.setWindowTitle(i18n("Resize all Pages")) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(dialog.accept) buttons.rejected.connect(dialog.reject) sizesBox = comics_export_dialog.comic_export_resize_widget( "Scale", batch=True, fileType=False) exporterSizes = comics_exporter.sizesCalculator() dialog.setLayout(QVBoxLayout()) dialog.layout().addWidget(sizesBox) dialog.layout().addWidget(buttons) if dialog.exec_() == QDialog.Accepted: progress = QProgressDialog(i18n("Resizing pages..."), str(), 0, len(self.setupDictionary["pages"])) progress.setWindowTitle(i18n("Resizing Pages")) progress.setCancelButton(None) timer = QElapsedTimer() timer.start() config = {} config = sizesBox.get_config(config) for p in range(len(self.setupDictionary["pages"])): absoluteUrl = os.path.join(self.projecturl, self.setupDictionary["pages"][p]) progress.setValue(p) timePassed = timer.elapsed() if (p > 0): timeEstimated = (len(self.setupDictionary["pages"]) - p) * (timePassed / p) passedString = str(int(timePassed / 60000)) + ":" + format( int(timePassed / 1000), "02d") + ":" + format( timePassed % 1000, "03d") estimatedString = str(int( timeEstimated / 60000)) + ":" + format( int(timeEstimated / 1000), "02d") + ":" + format( int(timeEstimated % 1000), "03d") progress.setLabelText( str( i18n( "{pages} of {pagesTotal} done. \nTime passed: {passedString}:\n Estimated:{estimated}" )).format(pages=p, pagesTotal=len( self.setupDictionary["pages"]), passedString=passedString, estimated=estimatedString)) qApp.processEvents() if os.path.exists(absoluteUrl): doc = Application.openDocument(absoluteUrl) listScales = exporterSizes.get_scale_from_resize_config( config["Scale"], [ doc.width(), doc.height(), doc.resolution(), doc.resolution() ]) doc.scaleImage(listScales[0], listScales[1], listScales[2], listScales[3], "bicubic") doc.waitForDone() doc.save() doc.waitForDone() doc.close() def slot_show_page_viewer(self): index = int(self.comicPageList.currentIndex().row()) self.page_viewer_dialog.load_comic(self.path_to_config) self.page_viewer_dialog.go_to_page_index(index) self.page_viewer_dialog.show() """ Function to copy the current project location into the clipboard. This is useful for users because they'll be able to use that url to quickly move to the project location in outside applications. """ def slot_copy_project_url(self): if self.projecturl is not None: clipboard = qApp.clipboard() clipboard.setText(str(self.projecturl)) """ Scrape text files with the textlayer keys for text, and put those in a POT file. This makes it possible to handle translations. """ def slot_scrape_translations(self): translationFolder = self.setupDictionary.get("translationLocation", "translations") fullTranslationPath = os.path.join(self.projecturl, translationFolder) os.makedirs(fullTranslationPath, exist_ok=True) textLayersToSearch = self.setupDictionary.get("textLayerNames", ["text"]) scraper = comics_project_translation_scraper.translation_scraper( self.projecturl, translationFolder, textLayersToSearch, self.setupDictionary["projectName"]) # Run text scraper. language = self.setupDictionary.get("language", "en") metadata = {} metadata["title"] = self.setupDictionary.get("title", "") metadata["summary"] = self.setupDictionary.get("summary", "") metadata["keywords"] = ", ".join( self.setupDictionary.get("otherKeywords", [""])) metadata["transnotes"] = self.setupDictionary.get( "translatorHeader", "Translator's Notes") scraper.start(self.setupDictionary["pages"], language, metadata) QMessageBox.information( self, i18n("Scraping success"), str(i18n("POT file has been written to: {file}")).format( file=fullTranslationPath), QMessageBox.Ok) """ This is required by the dockwidget class, otherwise unused. """ def canvasChanged(self, canvas): pass
class LocationCompleterView(QWidget): def __init__(self): super().__init__(None) self._view = None # QListView self._delegate = None # LocationCompleterDelegate self._searchEnginesLayout = None # QHBoxLayout self._resizeHeight = -1 self._resizeTimer = None # QTimer self._forceResize = True self.setAttribute(Qt.WA_ShowWithoutActivating) self.setAttribute(Qt.WA_X11NetWmWindowTypeCombo) if gVar.app.platformName() == 'xcb': self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint | Qt.BypassWindowManagerHint) else: self.setWindowFlags(Qt.Popup) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self._view = QListView(self) layout.addWidget(self._view) self._view.setUniformItemSizes(True) self._view.setEditTriggers(QAbstractItemView.NoEditTriggers) self._view.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel) self._view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._view.setSelectionBehavior(QAbstractItemView.SelectRows) self._view.setSelectionMode(QAbstractItemView.SingleSelection) self._view.setMouseTracking(True) gVar.app.installEventFilter(self) self._delegate = LocationCompleterDelegate(self) self._view.setItemDelegate(self._delegate) searchFrame = QFrame(self) searchFrame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised) searchLayout = QHBoxLayout(searchFrame) searchLayout.setContentsMargins(10, 4, 4, 4) searchSettingsButton = ToolButton(self) searchSettingsButton.setIcon(IconProvider.settingsIcon()) searchSettingsButton.setToolTip(_('Manage Search Engines')) searchSettingsButton.setAutoRaise(True) searchSettingsButton.setIconSize(QSize(16, 16)) searchSettingsButton.clicked.connect(self.searchEnginesDialogRequested) searchLabel = QLabel(_('Search with:')) self._searchEnginesLayout = QHBoxLayout() self._setupSearchEngines() gVar.app.searchEnginesManager().enginesChanged.connect( self._setupSearchEngines) searchLayout.addWidget(searchLabel) searchLayout.addLayout(self._searchEnginesLayout) searchLayout.addStretch() searchLayout.addWidget(searchSettingsButton) layout.addWidget(searchFrame) def model(self): ''' @return: QAbstractItemModel ''' return self._view.model() def setModel(self, model): ''' @param model QAbstractItemModel ''' self._view.setModel(model) def selectionModel(self): ''' @return: QItemSelectionModel ''' return self._view.selectionModel() def currentIndex(self): ''' @return: QModelIndex ''' return self._view.currentIndex() def setCurrentIndex(self, index): ''' @param index QModelIndex ''' self._view.setCurrentIndex(index) def adjustSize(self): maxItemsCount = 12 newHeight = self._view.sizeHintForRow(0) * min(maxItemsCount, self.model().rowCount()) if not self._resizeTimer: self._resizeTimer = QTimer(self) self._resizeTimer.setInterval(200) def func(): if self._resizeHeight > 0: self._view.setFixedHeight(self._resizeHeight) self.setFixedHeight(self.sizeHint().height()) self._resizeHeight = -1 self._resizeTimer.timeout.connect(func) if not self._forceResize: if newHeight == self._resizeHeight: return elif newHeight == self._view.height(): self._resizeHeight = -1 return elif newHeight < self._view.height(): self._resizeHeight = newHeight self._resizeTimer.start() return self._resizeHeight = -1 self._forceResize = False self._view.setFixedHeight(newHeight) self.setFixedHeight(self.sizeHint().height()) # override def eventFilter(self, obj, event): # noqa C901 ''' @param obj QObject @param event QEvent @return: bool ''' # Event filter based on QCompleter::eventFilter from qcompleter.cpp if obj == self or obj == self._view or not self.isVisible(): return False evtType = event.type() if obj == self._view.viewport(): if evtType == QEvent.MouseButtonRelease: # QMouseEvent e = event index = self._view.indexAt(e.pos()) if not index.isValid(): return False # Qt::MouseButton button = e.button() # Qt::KeyboardModifiers modifiers = e.modifiers() if button == Qt.LeftButton and modifiers == Qt.NoModifier: self.indexActivated.emit(index) return True if button == Qt.MiddleButton or (button == Qt.LeftButton and modifiers == Qt.ControlModifier): self.indexCtrlActivated.emit(index) return True if button == Qt.LeftButton and modifiers == Qt.ShiftModifier: self.indexShiftActivated.emit(index) return True return False if evtType == QEvent.KeyPress: # QKeyEvent keyEvent = event evtKey = keyEvent.key() modifiers = keyEvent.modifiers() index = self._view.currentIndex() item = self.model().index(0, 0) if item.data(LocationCompleterModel.VisitSearchItemRole): visitSearchIndex = item else: visitSearchIndex = QModelIndex() if (evtKey == Qt.Key_Up or evtKey == Qt.Key_Down) and \ self._view.currentIndex() != index: self._view.setCurrentIndex(index) # TODO: ? if evtKey in (Qt.Key_Return, Qt.Key_Enter): if index.isValid(): if modifiers == Qt.NoModifier or modifiers == Qt.KeypadModifier: self.indexActivated.emit(index) return True if modifiers == Qt.ControlModifier: self.indexCtrlActivated.emit(index) return True if modifiers == Qt.ShiftModifier: self.indexShiftActivated.emit(index) return True elif evtKey == Qt.Key_End: if modifiers & Qt.ControlModifier: self._view.setCurrentIndex(self.model().index( self.model().rowCount() - 1, 0)) return True else: self.close() elif evtKey == Qt.Key_Home: if modifiers & Qt.ControlModifier: self._view.setCurrentIndex(self.model().index(0, 0)) self._view.scrollToTop() return True else: self.close() elif evtKey == Qt.Key_Escape: self.close() return True elif evtKey == Qt.Key_F4: if modifiers == Qt.AltModifier: self.close() return False elif evtKey in (Qt.Key_Tab, Qt.Key_Backtab): if modifiers != Qt.NoModifier and modifiers != Qt.ShiftModifier: return False isBack = evtKey == Qt.Key_Backtab if evtKey == Qt.Key_Tab and modifiers == Qt.ShiftModifier: isBack = True ev = QKeyEvent(QKeyEvent.KeyPress, isBack and Qt.Key_Up or Qt.Key_Down, Qt.NoModifier) QApplication.sendEvent(self.focusProxy(), ev) return True elif evtKey in (Qt.Key_Up, Qt.Key_PageUp): if modifiers != Qt.NoModifier: return False step = evtKey == Qt.Key_PageUp and 5 or 1 if not index.isValid() or index == visitSearchIndex: rowCount = self.model().rowCount() lastIndex = self.model().index(rowCount - 1, 0) self._view.setCurrentIndex(lastIndex) elif index.row() == 0: self._view.setCurrentIndex(QModelIndex()) else: row = max(0, index.row() - step) self._view.setCurrentIndex(self.model().index(row, 0)) return True elif evtKey in (Qt.Key_Down, Qt.Key_PageDown): if modifiers != Qt.NoModifier: return False step = evtKey == Qt.Key_PageDown and 5 or 1 if not index.isValid(): firstIndex = self.model().index(0, 0) self._view.setCurrentIndex(firstIndex) elif index != visitSearchIndex and index.row( ) == self.model().rowCount() - 1: self._view.setCurrentIndex(visitSearchIndex) self._view.scrollToTop() else: row = min(self.model().rowCount() - 1, index.row() + step) self._view.setCurrentIndex(self.model().index(row, 0)) return True elif evtKey == Qt.Key_Delete: if index != visitSearchIndex and self._view.viewport().rect( ).contains(self._view.visualRect(index)): self.indexDeleteRequested.emit(index) return True elif evtKey == Qt.Key_Shift: self._delegate.setForceVisitItem(True) self._view.viewport().update() # end of switch evtKey if self.focusProxy(): self.focusProxy().event(keyEvent) return True elif evtType == QEvent.KeyRelease: if event.key() == Qt.Key_Shift: self._delegate.setForceVisitItem(False) self._view.viewport().update() return True elif evtType in (QEvent.Wheel, QEvent.MouseButtonPress): if not self.underMouse(): self.close() return False elif evtType == QEvent.FocusOut: # QFocusEvent focusEvent = event reason = focusEvent.reason() if reason != Qt.PopupFocusReason and reason != Qt.MouseFocusReason: self.close() elif evtType in (QEvent.Move, QEvent.Resize): w = obj if isinstance(w, QWidget) and w.isWindow() and self.focusProxy( ) and w == self.focusProxy().window(): self.close() # end of switch evtType return False # Q_SIGNALS closed = pyqtSignal() searchEnginesDialogRequested = pyqtSignal() loadRequested = pyqtSignal(LoadRequest) indexActivated = pyqtSignal(QModelIndex) indexCtrlActivated = pyqtSignal(QModelIndex) indexShiftActivated = pyqtSignal(QModelIndex) indexDeleteRequested = pyqtSignal(QModelIndex) # public Q_SLOTS: def close(self): self.hide() self._view.verticalScrollBar().setValue(0) self._delegate.setForceVisitItem(False) self._forceResize = True self.closed.emit() # private: def _setupSearchEngines(self): for idx in (range(self._searchEnginesLayout.count())): item = self._searchEnginesLayout.takeAt(0) item.deleteLater() engines = gVar.app.searchEnginesManager().allEngines() for engine in engines: button = ToolButton(self) button.setIcon(engine.icon) button.setToolTip(engine.name) button.setAutoRaise(True) button.setIconSize(QSize(16, 16)) def func(): text = self.model().index(0, 0).data( LocationCompleterModel.SearchStringRole) self.loadRequested.emit( gVar.app.searchEngineManager().searchResult(engine, text)) button.clicked.connect(func) self._searchEnginesLayout.addWidget(button)
class comic_export_setting_dialog(QDialog): acbfStylesList = [ "speech", "commentary", "formal", "letter", "code", "heading", "audio", "thought", "sign", "sound", "emphasis", "strong" ] def __init__(self): super().__init__() self.setLayout(QVBoxLayout()) self.setWindowTitle(i18n("Export Settings")) buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) mainWidget = QTabWidget() self.layout().addWidget(mainWidget) self.layout().addWidget(buttons) # Set basic crop settings # Set which layers to remove before export. mainExportSettings = QWidget() mainExportSettings.setLayout(QVBoxLayout()) groupExportCrop = QGroupBox(i18n("Crop Settings")) formCrop = QFormLayout() groupExportCrop.setLayout(formCrop) self.chk_toOutmostGuides = QCheckBox(i18n("Crop to outmost guides")) self.chk_toOutmostGuides.setChecked(True) self.chk_toOutmostGuides.setToolTip( i18n( "This will crop to the outmost guides if possible and otherwise use the underlying crop settings." )) formCrop.addRow("", self.chk_toOutmostGuides) btn_fromSelection = QPushButton( i18n("Set Margins from Active Selection")) btn_fromSelection.clicked.connect(self.slot_set_margin_from_selection) # This doesn't work. formCrop.addRow("", btn_fromSelection) self.spn_marginLeft = QSpinBox() self.spn_marginLeft.setMaximum(99999) self.spn_marginLeft.setSuffix(" px") formCrop.addRow(i18n("Left:"), self.spn_marginLeft) self.spn_marginTop = QSpinBox() self.spn_marginTop.setMaximum(99999) self.spn_marginTop.setSuffix(" px") formCrop.addRow(i18n("Top:"), self.spn_marginTop) self.spn_marginRight = QSpinBox() self.spn_marginRight.setMaximum(99999) self.spn_marginRight.setSuffix(" px") formCrop.addRow(i18n("Right:"), self.spn_marginRight) self.spn_marginBottom = QSpinBox() self.spn_marginBottom.setMaximum(99999) self.spn_marginBottom.setSuffix(" px") formCrop.addRow(i18n("Bottom:"), self.spn_marginBottom) groupExportLayers = QGroupBox(i18n("Layers")) formLayers = QFormLayout() groupExportLayers.setLayout(formLayers) self.cmbLabelsRemove = labelSelector() formLayers.addRow(i18n("Label for removal:"), self.cmbLabelsRemove) self.ln_text_layer_name = QLineEdit() self.ln_text_layer_name.setToolTip( i18n( "These are keywords that can be used to identify text layers. A layer only needs to contain the keyword to be recognized. Keywords should be comma separated." )) self.ln_panel_layer_name = QLineEdit() self.ln_panel_layer_name.setToolTip( i18n( "These are keywords that can be used to identify panel layers. A layer only needs to contain the keyword to be recognized. Keywords should be comma separated." )) formLayers.addRow(i18n("Text Layer Key:"), self.ln_text_layer_name) formLayers.addRow(i18n("Panel Layer Key:"), self.ln_panel_layer_name) mainExportSettings.layout().addWidget(groupExportCrop) mainExportSettings.layout().addWidget(groupExportLayers) mainWidget.addTab(mainExportSettings, i18n("General")) # CBZ, crop, resize, which metadata to add. CBZexportSettings = QWidget() CBZexportSettings.setLayout(QVBoxLayout()) self.CBZactive = QCheckBox(i18n("Export to CBZ")) CBZexportSettings.layout().addWidget(self.CBZactive) self.CBZgroupResize = comic_export_resize_widget("CBZ") CBZexportSettings.layout().addWidget(self.CBZgroupResize) self.CBZactive.clicked.connect(self.CBZgroupResize.setEnabled) CBZgroupMeta = QGroupBox(i18n("Metadata to Add")) # CBZexportSettings.layout().addWidget(CBZgroupMeta) CBZgroupMeta.setLayout(QFormLayout()) mainWidget.addTab(CBZexportSettings, i18n("CBZ")) # ACBF, crop, resize, creator name, version history, panel layer, text layers. ACBFExportSettings = QWidget() ACBFform = QFormLayout() ACBFExportSettings.setLayout(QVBoxLayout()) ACBFdocInfo = QGroupBox() ACBFdocInfo.setTitle(i18n("ACBF Document Info")) ACBFdocInfo.setLayout(ACBFform) self.lnACBFID = QLabel() self.lnACBFID.setToolTip( i18n( "By default this will be filled with a generated universal unique identifier. The ID by itself is merely so that comic book library management programs can figure out if this particular comic is already in their database and whether it has been rated. Of course, the UUID can be changed into something else by manually changing the JSON, but this is advanced usage." )) self.spnACBFVersion = QSpinBox() self.ACBFhistoryModel = QStandardItemModel() acbfHistoryList = QListView() acbfHistoryList.setModel(self.ACBFhistoryModel) btn_add_history = QPushButton(i18n("Add History Entry")) btn_add_history.clicked.connect(self.slot_add_history_item) self.chkIncludeTranslatorComments = QCheckBox() self.chkIncludeTranslatorComments.setText( i18n("Include translator's comments")) self.chkIncludeTranslatorComments.setToolTip( i18n( "A PO file can contain translator's comments. If this is checked, the translations comments will be added as references into the ACBF file." )) self.lnTranslatorHeader = QLineEdit() ACBFform.addRow(i18n("ACBF UID:"), self.lnACBFID) ACBFform.addRow(i18n("Version:"), self.spnACBFVersion) ACBFform.addRow(i18n("Version history:"), acbfHistoryList) ACBFform.addRow("", btn_add_history) ACBFform.addRow("", self.chkIncludeTranslatorComments) ACBFform.addRow(i18n("Translator header:"), self.lnTranslatorHeader) ACBFAuthorInfo = QWidget() acbfAVbox = QVBoxLayout(ACBFAuthorInfo) infoLabel = QLabel( i18n( "The people responsible for the generation of the CBZ/ACBF files." )) infoLabel.setWordWrap(True) ACBFAuthorInfo.layout().addWidget(infoLabel) self.ACBFauthorModel = QStandardItemModel(0, 6) labels = [ i18n("Nick Name"), i18n("Given Name"), i18n("Middle Name"), i18n("Family Name"), i18n("Email"), i18n("Homepage") ] self.ACBFauthorModel.setHorizontalHeaderLabels(labels) self.ACBFauthorTable = QTableView() acbfAVbox.addWidget(self.ACBFauthorTable) self.ACBFauthorTable.setModel(self.ACBFauthorModel) self.ACBFauthorTable.verticalHeader().setDragEnabled(True) self.ACBFauthorTable.verticalHeader().setDropIndicatorShown(True) self.ACBFauthorTable.verticalHeader().setSectionsMovable(True) self.ACBFauthorTable.verticalHeader().sectionMoved.connect( self.slot_reset_author_row_visual) AuthorButtons = QHBoxLayout() btn_add_author = QPushButton(i18n("Add Author")) btn_add_author.clicked.connect(self.slot_add_author) AuthorButtons.addWidget(btn_add_author) btn_remove_author = QPushButton(i18n("Remove Author")) btn_remove_author.clicked.connect(self.slot_remove_author) AuthorButtons.addWidget(btn_remove_author) acbfAVbox.addLayout(AuthorButtons) ACBFStyle = QWidget() ACBFStyle.setLayout(QHBoxLayout()) self.ACBFStylesModel = QStandardItemModel() self.ACBFStyleClass = QListView() self.ACBFStyleClass.setModel(self.ACBFStylesModel) ACBFStyle.layout().addWidget(self.ACBFStyleClass) ACBFStyleEdit = QWidget() ACBFStyleEditVB = QVBoxLayout(ACBFStyleEdit) self.ACBFuseFont = QCheckBox(i18n("Use font")) self.ACBFFontList = QListView() self.ACBFFontList.setItemDelegate(font_list_delegate()) self.ACBFuseFont.toggled.connect(self.font_slot_enable_font_view) self.ACBFFontListModel = QStandardItemModel() self.ACBFFontListModel.rowsRemoved.connect( self.slot_font_current_style) self.ACBFFontListModel.itemChanged.connect( self.slot_font_current_style) self.btnAcbfAddFont = QPushButton() self.btnAcbfAddFont.setIcon(Application.icon("list-add")) self.btnAcbfAddFont.clicked.connect(self.font_slot_add_font) self.btn_acbf_remove_font = QPushButton() self.btn_acbf_remove_font.setIcon(Application.icon("edit-delete")) self.btn_acbf_remove_font.clicked.connect(self.font_slot_remove_font) self.ACBFFontList.setModel(self.ACBFFontListModel) self.ACBFdefaultFont = QComboBox() self.ACBFdefaultFont.addItems( ["sans-serif", "serif", "monospace", "cursive", "fantasy"]) acbfFontButtons = QHBoxLayout() acbfFontButtons.addWidget(self.btnAcbfAddFont) acbfFontButtons.addWidget(self.btn_acbf_remove_font) self.ACBFBold = QCheckBox(i18n("Bold")) self.ACBFItal = QCheckBox(i18n("Italic")) self.ACBFStyleClass.clicked.connect(self.slot_set_style) self.ACBFStyleClass.selectionModel().selectionChanged.connect( self.slot_set_style) self.ACBFStylesModel.itemChanged.connect(self.slot_set_style) self.ACBFBold.toggled.connect(self.slot_font_current_style) self.ACBFItal.toggled.connect(self.slot_font_current_style) colorWidget = QGroupBox(self) colorWidget.setTitle(i18n("Text Colors")) colorWidget.setLayout(QVBoxLayout()) self.regularColor = QColorDialog() self.invertedColor = QColorDialog() self.btn_acbfRegColor = QPushButton(i18n("Regular Text"), self) self.btn_acbfRegColor.clicked.connect(self.slot_change_regular_color) self.btn_acbfInvColor = QPushButton(i18n("Inverted Text"), self) self.btn_acbfInvColor.clicked.connect(self.slot_change_inverted_color) colorWidget.layout().addWidget(self.btn_acbfRegColor) colorWidget.layout().addWidget(self.btn_acbfInvColor) ACBFStyleEditVB.addWidget(colorWidget) ACBFStyleEditVB.addWidget(self.ACBFuseFont) ACBFStyleEditVB.addWidget(self.ACBFFontList) ACBFStyleEditVB.addLayout(acbfFontButtons) ACBFStyleEditVB.addWidget(self.ACBFdefaultFont) ACBFStyleEditVB.addWidget(self.ACBFBold) ACBFStyleEditVB.addWidget(self.ACBFItal) ACBFStyleEditVB.addStretch() ACBFStyle.layout().addWidget(ACBFStyleEdit) ACBFTabwidget = QTabWidget() ACBFTabwidget.addTab(ACBFdocInfo, i18n("Document Info")) ACBFTabwidget.addTab(ACBFAuthorInfo, i18n("Author Info")) ACBFTabwidget.addTab(ACBFStyle, i18n("Style Sheet")) ACBFExportSettings.layout().addWidget(ACBFTabwidget) mainWidget.addTab(ACBFExportSettings, i18n("ACBF")) # Epub export, crop, resize, other questions. EPUBexportSettings = QWidget() EPUBexportSettings.setLayout(QVBoxLayout()) self.EPUBactive = QCheckBox(i18n("Export to EPUB")) EPUBexportSettings.layout().addWidget(self.EPUBactive) self.EPUBgroupResize = comic_export_resize_widget("EPUB") EPUBexportSettings.layout().addWidget(self.EPUBgroupResize) self.EPUBactive.clicked.connect(self.EPUBgroupResize.setEnabled) mainWidget.addTab(EPUBexportSettings, i18n("EPUB")) # For Print. Crop, no resize. TIFFExportSettings = QWidget() TIFFExportSettings.setLayout(QVBoxLayout()) self.TIFFactive = QCheckBox(i18n("Export to TIFF")) TIFFExportSettings.layout().addWidget(self.TIFFactive) self.TIFFgroupResize = comic_export_resize_widget("TIFF") TIFFExportSettings.layout().addWidget(self.TIFFgroupResize) self.TIFFactive.clicked.connect(self.TIFFgroupResize.setEnabled) mainWidget.addTab(TIFFExportSettings, i18n("TIFF")) # SVG, crop, resize, embed vs link. #SVGExportSettings = QWidget() #mainWidget.addTab(SVGExportSettings, i18n("SVG")) """ Add a history item to the acbf version history list. """ def slot_add_history_item(self): newItem = QStandardItem() newItem.setText( str(i18n("v{version}-in this version...")).format( version=str(self.spnACBFVersion.value()))) self.ACBFhistoryModel.appendRow(newItem) """ Get the margins by treating the active selection in a document as the trim area. This allows people to snap selections to a vector or something, and then get the margins. """ def slot_set_margin_from_selection(self): doc = Application.activeDocument() if doc is not None: if doc.selection() is not None: self.spn_marginLeft.setValue(doc.selection().x()) self.spn_marginTop.setValue(doc.selection().y()) self.spn_marginRight.setValue(doc.width() - (doc.selection().x() + doc.selection().width())) self.spn_marginBottom.setValue(doc.height() - (doc.selection().y() + doc.selection().height())) """ Add an author with default values initialised. """ def slot_add_author(self): listItems = [] listItems.append(QStandardItem(i18n("Anon"))) # Nick name listItems.append(QStandardItem(i18n("John"))) # First name listItems.append(QStandardItem()) # Middle name listItems.append(QStandardItem(i18n("Doe"))) # Last name listItems.append(QStandardItem()) # email listItems.append(QStandardItem()) # homepage self.ACBFauthorModel.appendRow(listItems) """ Remove the selected author from the author list. """ def slot_remove_author(self): self.ACBFauthorModel.removeRow( self.ACBFauthorTable.currentIndex().row()) """ Ensure that the drag and drop of authors doesn't mess up the labels. """ def slot_reset_author_row_visual(self): headerLabelList = [] for i in range(self.ACBFauthorTable.verticalHeader().count()): headerLabelList.append(str(i)) for i in range(self.ACBFauthorTable.verticalHeader().count()): logicalI = self.ACBFauthorTable.verticalHeader().logicalIndex(i) headerLabelList[logicalI] = str(i + 1) self.ACBFauthorModel.setVerticalHeaderLabels(headerLabelList) """ Set the style item to the gui item's style. """ def slot_set_style(self): index = self.ACBFStyleClass.currentIndex() if index.isValid(): item = self.ACBFStylesModel.item(index.row()) fontUsed = item.data(role=styleEnum.FONT) if fontUsed is not None: self.ACBFuseFont.setChecked(fontUsed) else: self.ACBFuseFont.setChecked(False) self.font_slot_enable_font_view() fontList = item.data(role=styleEnum.FONTLIST) self.ACBFFontListModel.clear() for font in fontList: NewItem = QStandardItem(font) NewItem.setEditable(True) self.ACBFFontListModel.appendRow(NewItem) self.ACBFdefaultFont.setCurrentText( str(item.data(role=styleEnum.FONTGENERIC))) bold = item.data(role=styleEnum.BOLD) if bold is not None: self.ACBFBold.setChecked(bold) else: self.ACBFBold.setChecked(False) italic = item.data(role=styleEnum.ITALIC) if italic is not None: self.ACBFItal.setChecked(italic) else: self.ACBFItal.setChecked(False) """ Set the gui items to the currently selected style. """ def slot_font_current_style(self): index = self.ACBFStyleClass.currentIndex() if index.isValid(): item = self.ACBFStylesModel.item(index.row()) fontList = [] for row in range(self.ACBFFontListModel.rowCount()): font = self.ACBFFontListModel.item(row) fontList.append(font.text()) item.setData(self.ACBFuseFont.isChecked(), role=styleEnum.FONT) item.setData(fontList, role=styleEnum.FONTLIST) item.setData(self.ACBFdefaultFont.currentText(), role=styleEnum.FONTGENERIC) item.setData(self.ACBFBold.isChecked(), role=styleEnum.BOLD) item.setData(self.ACBFItal.isChecked(), role=styleEnum.ITALIC) self.ACBFStylesModel.setItem(index.row(), item) """ Change the regular color """ def slot_change_regular_color(self): if (self.regularColor.exec_() == QDialog.Accepted): square = QPixmap(32, 32) square.fill(self.regularColor.currentColor()) self.btn_acbfRegColor.setIcon(QIcon(square)) """ change the inverted color """ def slot_change_inverted_color(self): if (self.invertedColor.exec_() == QDialog.Accepted): square = QPixmap(32, 32) square.fill(self.invertedColor.currentColor()) self.btn_acbfInvColor.setIcon(QIcon(square)) def font_slot_enable_font_view(self): self.ACBFFontList.setEnabled(self.ACBFuseFont.isChecked()) self.btn_acbf_remove_font.setEnabled(self.ACBFuseFont.isChecked()) self.btnAcbfAddFont.setEnabled(self.ACBFuseFont.isChecked()) self.ACBFdefaultFont.setEnabled(self.ACBFuseFont.isChecked()) if self.ACBFFontListModel.rowCount() < 2: self.btn_acbf_remove_font.setEnabled(False) def font_slot_add_font(self): NewItem = QStandardItem(QFont().family()) NewItem.setEditable(True) self.ACBFFontListModel.appendRow(NewItem) def font_slot_remove_font(self): index = self.ACBFFontList.currentIndex() if index.isValid(): self.ACBFFontListModel.removeRow(index.row()) if self.ACBFFontListModel.rowCount() < 2: self.btn_acbf_remove_font.setEnabled(False) """ Load the UI values from the config dictionary given. """ def setConfig(self, config): if "cropToGuides" in config.keys(): self.chk_toOutmostGuides.setChecked(config["cropToGuides"]) if "cropLeft" in config.keys(): self.spn_marginLeft.setValue(config["cropLeft"]) if "cropTop" in config.keys(): self.spn_marginTop.setValue(config["cropTop"]) if "cropRight" in config.keys(): self.spn_marginRight.setValue(config["cropRight"]) if "cropBottom" in config.keys(): self.spn_marginBottom.setValue(config["cropBottom"]) if "labelsToRemove" in config.keys(): self.cmbLabelsRemove.setLabels(config["labelsToRemove"]) if "textLayerNames" in config.keys(): self.ln_text_layer_name.setText(", ".join( config["textLayerNames"])) else: self.ln_text_layer_name.setText("text") if "panelLayerNames" in config.keys(): self.ln_panel_layer_name.setText(", ".join( config["panelLayerNames"])) else: self.ln_panel_layer_name.setText("panels") self.CBZgroupResize.set_config(config) if "CBZactive" in config.keys(): self.CBZactive.setChecked(config["CBZactive"]) self.EPUBgroupResize.set_config(config) if "EPUBactive" in config.keys(): self.EPUBactive.setChecked(config["EPUBactive"]) self.TIFFgroupResize.set_config(config) if "TIFFactive" in config.keys(): self.TIFFactive.setChecked(config["TIFFactive"]) if "acbfAuthor" in config.keys(): if isinstance(config["acbfAuthor"], list): for author in config["acbfAuthor"]: listItems = [] listItems.append(QStandardItem(author.get("nickname", ""))) listItems.append( QStandardItem(author.get("first-name", ""))) listItems.append(QStandardItem(author.get("initials", ""))) listItems.append(QStandardItem(author.get("last-name", ""))) listItems.append(QStandardItem(author.get("email", ""))) listItems.append(QStandardItem(author.get("homepage", ""))) self.ACBFauthorModel.appendRow(listItems) pass else: listItems = [] listItems.append(QStandardItem( config["acbfAuthor"])) # Nick name for i in range(0, 5): listItems.append(QStandardItem()) # First name self.ACBFauthorModel.appendRow(listItems) if "uuid" in config.keys(): self.lnACBFID.setText(config["uuid"]) elif "acbfID" in config.keys(): self.lnACBFID.setText(config["acbfID"]) else: config["uuid"] = QUuid.createUuid().toString() self.lnACBFID.setText(config["uuid"]) if "acbfVersion" in config.keys(): self.spnACBFVersion.setValue(config["acbfVersion"]) if "acbfHistory" in config.keys(): for h in config["acbfHistory"]: item = QStandardItem() item.setText(h) self.ACBFhistoryModel.appendRow(item) if "acbfStyles" in config.keys(): styleDict = config.get("acbfStyles", {}) for key in self.acbfStylesList: keyDict = styleDict.get(key, {}) style = QStandardItem(key.title()) style.setCheckable(True) if key in styleDict.keys(): style.setCheckState(Qt.Checked) else: style.setCheckState(Qt.Unchecked) fontOn = False if "font" in keyDict.keys() or "genericfont" in keyDict.keys(): fontOn = True style.setData(fontOn, role=styleEnum.FONT) if "font" in keyDict: fontlist = keyDict["font"] if isinstance(fontlist, list): font = keyDict.get("font", QFont().family()) style.setData(font, role=styleEnum.FONTLIST) else: style.setData([fontlist], role=styleEnum.FONTLIST) else: style.setData([QFont().family()], role=styleEnum.FONTLIST) style.setData(keyDict.get("genericfont", "sans-serif"), role=styleEnum.FONTGENERIC) style.setData(keyDict.get("bold", False), role=styleEnum.BOLD) style.setData(keyDict.get("ital", False), role=styleEnum.ITALIC) self.ACBFStylesModel.appendRow(style) keyDict = styleDict.get("general", {}) self.regularColor.setCurrentColor( QColor(keyDict.get("color", "#000000"))) square = QPixmap(32, 32) square.fill(self.regularColor.currentColor()) self.btn_acbfRegColor.setIcon(QIcon(square)) keyDict = styleDict.get("inverted", {}) self.invertedColor.setCurrentColor( QColor(keyDict.get("color", "#FFFFFF"))) square.fill(self.invertedColor.currentColor()) self.btn_acbfInvColor.setIcon(QIcon(square)) else: for key in self.acbfStylesList: style = QStandardItem(key.title()) style.setCheckable(True) style.setCheckState(Qt.Unchecked) style.setData(False, role=styleEnum.FONT) style.setData(QFont().family(), role=styleEnum.FONTLIST) style.setData("sans-serif", role=styleEnum.FONTGENERIC) style.setData(False, role=styleEnum.BOLD) #Bold style.setData(False, role=styleEnum.ITALIC) #Italic self.ACBFStylesModel.appendRow(style) self.CBZgroupResize.setEnabled(self.CBZactive.isChecked()) self.lnTranslatorHeader.setText( config.get("translatorHeader", "Translator's Notes")) self.chkIncludeTranslatorComments.setChecked( config.get("includeTranslComment", False)) """ Store the GUI values into the config dictionary given. @return the config diactionary filled with new values. """ def getConfig(self, config): config["cropToGuides"] = self.chk_toOutmostGuides.isChecked() config["cropLeft"] = self.spn_marginLeft.value() config["cropTop"] = self.spn_marginTop.value() config["cropBottom"] = self.spn_marginRight.value() config["cropRight"] = self.spn_marginBottom.value() config["labelsToRemove"] = self.cmbLabelsRemove.getLabels() config["CBZactive"] = self.CBZactive.isChecked() config = self.CBZgroupResize.get_config(config) config["EPUBactive"] = self.EPUBactive.isChecked() config = self.EPUBgroupResize.get_config(config) config["TIFFactive"] = self.TIFFactive.isChecked() config = self.TIFFgroupResize.get_config(config) authorList = [] for row in range(self.ACBFauthorTable.verticalHeader().count()): logicalIndex = self.ACBFauthorTable.verticalHeader().logicalIndex( row) listEntries = [ "nickname", "first-name", "initials", "last-name", "email", "homepage" ] author = {} for i in range(len(listEntries)): entry = self.ACBFauthorModel.data( self.ACBFauthorModel.index(logicalIndex, i)) if entry is None: entry = " " if entry.isspace() is False and len(entry) > 0: author[listEntries[i]] = entry elif listEntries[i] in author.keys(): author.pop(listEntries[i]) authorList.append(author) config["acbfAuthor"] = authorList config["acbfVersion"] = self.spnACBFVersion.value() versionList = [] for r in range(self.ACBFhistoryModel.rowCount()): index = self.ACBFhistoryModel.index(r, 0) versionList.append( self.ACBFhistoryModel.data(index, Qt.DisplayRole)) config["acbfHistory"] = versionList acbfStylesDict = {} for row in range(0, self.ACBFStylesModel.rowCount()): entry = self.ACBFStylesModel.item(row) if entry.checkState() == Qt.Checked: key = entry.text().lower() style = {} if entry.data(role=styleEnum.FONT): font = entry.data(role=styleEnum.FONTLIST) if font is not None: style["font"] = font genericfont = entry.data(role=styleEnum.FONTGENERIC) if font is not None: style["genericfont"] = genericfont bold = entry.data(role=styleEnum.BOLD) if bold is not None: style["bold"] = bold italic = entry.data(role=styleEnum.ITALIC) if italic is not None: style["ital"] = italic acbfStylesDict[key] = style acbfStylesDict["general"] = { "color": self.regularColor.currentColor().name() } acbfStylesDict["inverted"] = { "color": self.invertedColor.currentColor().name() } config["acbfStyles"] = acbfStylesDict config["translatorHeader"] = self.lnTranslatorHeader.text() config[ "includeTranslComment"] = self.chkIncludeTranslatorComments.isChecked( ) # Turn this into something that retrieves from a line-edit when string freeze is over. config["textLayerNames"] = self.ln_text_layer_name.text().split(",") config["panelLayerNames"] = self.ln_panel_layer_name.text().split(",") return config
class MainWindow(QMainWindow): graph_legend = [] def __init__(self): super().__init__() self.setWindowTitle('GraphMaster') self.setWindowIcon(QIcon('../Icons/formula.png')) self.setGeometry(400, 400, 900, 600) self.MyUI() def MyUI(self): self.fig, self.axes = self.plot_sigle_empty_graph() self.canvas = Canvas(self.fig) self.toolbar = NavigationToolbar(self.canvas, self) self.v_layout = QVBoxLayout() self.h_layout = QHBoxLayout() self.list_view = QListView() self.plot_dots_model = DsaGraphicalObjectsModel() self.list_view.setModel(self.plot_dots_model) self.btn_clear = QPushButton('Delete') self.btn_clear.clicked.connect(self.remove_plot) self.v_layout.addWidget(self.canvas) self.v_layout.addWidget(self.toolbar) self.lbl_func = QLabel() self.lbl_func.setPixmap( QPixmap('../Icons/function-mathematical-symbol.png')) self.f_field = QLineEdit() self.h_layout.addWidget(self.lbl_func) self.h_layout.addWidget(self.f_field) self.layout = QGridLayout() self.btn = QPushButton('Plot') self.btn.clicked.connect(self.on_clicked_plot) self.layout.addLayout(self.h_layout, 0, 0, 1, 6) self.layout.addWidget(self.btn, 1, 4, 1, 2) self.layout.addWidget(self.btn_clear, 1, 0, 1, 2) self.layout.addLayout(self.v_layout, 0, 6, 5, 5) self.layout.addWidget(self.list_view, 2, 0, 5, 6) self.central_widget = QWidget() self.central_widget.setLayout(self.layout) self.setCentralWidget(self.central_widget) def get_f_str(self): return self.f_field.text() def on_clicked_plot(self): self.plot() def plot_sigle_empty_graph(self): fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(10, 7), dpi=100, facecolor='grey', frameon=True, edgecolor='black', linewidth=1) fig.subplots_adjust(wspace=0.4, hspace=0.6, left=0.15, right=0.85, top=0.9, bottom=0.1) axes.grid(True, c='lightgrey', alpha=0.7) axes.set_title('Diagram Header', fontsize=10) axes.set_xlabel('X', fontsize=8) axes.set_ylabel('Y', fontsize=8) return fig, axes def plot_custom_function(self, axes=None, function=None, legend=None, name=None, limits=None, type='y=f(x)'): left_limit = limits[0] right_limit = limits[1] step = (max(limits) - min(limits)) / 100000 if type == 'y=f(x)': legend.append('y=' + str(function)) x_vals = np.arange(left_limit, right_limit, step) f = StringFunction(function) y_vals = [f.calculate_f(x) for x in x_vals] plot_instance = axes.plot(x_vals, y_vals, '-', lw=1) axes.set_xlim(left_limit, right_limit) axes.set_ylim(left_limit, right_limit) axes.legend(legend, loc='best', fontsize=8) return plot_instance def plot(self): function = self.f_field.text() instance = self.plot_custom_function(axes=self.axes, function=function, legend=self.graph_legend, limits=[0.01, 40]) self.fig.canvas.draw() self.plot_dots_model.insertRows(0, 1, data=['y=' + function, instance]) def remove_plot(self): index = self.list_view.currentIndex() position = index.row() model = index.model() model.removeRows(position=position, rows=1) self.fig.canvas.draw()
class CollectData(QWidget): def __init__(self): super().__init__() self.init_variable() self.init_img() self.init_ui() self.show() ''' def paintEvent(self, QPaintEvent): painter = QPainter(self) painter.setPen(QColor(166,66,250)) painter.begin(self) painter.draw() painter.end() ''' def init_img(self): self.qlabel = myLabel(self) img = cv2.imread('data/test.png') # 打开图片 self.qlabel.img = img.copy() self.qlabel.img_current = img.copy() self.qlabel.update_img() def init_variable(self): self.label = 0 self.transformation_type = 0 self.total_img_number = 0 self.current_img_index = 0 self.folder_path = r"data" self.jump_img_index = -1 self.img_list = [] self.img_name_list = [] self.whether_to_crop = 0 def init_ui(self): self.setGeometry(200, 200, 1000, 800) self.setWindowTitle('数据标注') self.qlabel.setGeometry(QRect(30, 30, 640, 480)) self.init_buttons() for file_name in os.listdir(self.folder_path + '/'): img = cv2.imread(self.folder_path + '/' + file_name) if img is None: continue self.img_list.append(img) self.img_name_list.append(os.path.splitext(file_name)[0]) #QMessageBox.information(self, 'complete', '图片加载完毕') self.total_img_number = len(self.img_list) self.current_img_index = 1 self.refresh_img() self.update_list() def init_buttons(self): self.previous_img_button = QPushButton("上一张图片", self) self.next_img_button = QPushButton("下一张图片", self) self.save_message_button = QPushButton("保存当前图片信息", self) self.show_message_button = QPushButton("显示当前图片信息", self) self.open_folder_button = QPushButton("打开文件夹", self) self.add_border_button = QPushButton("保存当前框", self) self.delete_border_button = QPushButton("删除选中框", self) self.img_folder_text = QLineEdit('data', self) self.goto_chosen_img_button = QPushButton("跳转图片", self) self.jump_img_text = QLineEdit('', self) self.show_index_message = QLabel(self) self.crop_message_box = QCheckBox('裁剪所选图片', self) self.img_folder_text.selectAll() self.img_folder_text.setFocus() self.previous_img_button.setGeometry(30, 530, 150, 40) self.next_img_button.setGeometry(200, 530, 150, 40) self.save_message_button.setGeometry(370, 530, 150, 40) self.show_message_button.setGeometry(540, 530, 150, 40) self.img_folder_text.setGeometry(30, 590, 660, 40) self.open_folder_button.setGeometry(710, 590, 150, 40) self.jump_img_text.setGeometry(30, 650, 150, 40) self.goto_chosen_img_button.setGeometry(200, 650, 150, 40) self.show_index_message.setGeometry(30, 710, 300, 40) self.crop_message_box.setGeometry(30, 750, 150, 40) self.add_border_button.setGeometry(710, 380, 150, 40) self.delete_border_button.setGeometry(710, 440, 150, 40) self.previous_img_button.clicked.connect(self.previous_img) self.next_img_button.clicked.connect(self.next_img) self.save_message_button.clicked.connect(self.save_message) self.show_message_button.clicked.connect(self.show_message) self.open_folder_button.clicked.connect(self.open_folder) self.add_border_button.clicked.connect(self.save_current_border) self.delete_border_button.clicked.connect(self.delete_border) self.goto_chosen_img_button.clicked.connect(self.goto_chosen_img) self.crop_message_box.stateChanged.connect(self.crop_message) self.label_combo = QComboBox(self) for i in range(len(LABEL_LIST)): self.label_combo.addItem(LABEL_LIST[i]) self.label_combo.move(900, 30) self.label_combo.activated[str].connect(self.label_on_activated) self.listview = QListView(self) self.listview.setGeometry(710, 30, 150, 320) self.listview.doubleClicked.connect(self.list_clicked) self.listview.setEditTriggers(QListView.NoEditTriggers) def crop_message(self): self.whether_to_crop = self.crop_message_box.checkState() def previous_img(self): if self.current_img_index == 1: QMessageBox.information(self, 'warning', '已经是第一张啦') return self.current_img_index -= 1 self.refresh_img() def next_img(self): if self.current_img_index == self.total_img_number: QMessageBox.information(self, 'warning', '已经是最后一张啦') return self.current_img_index += 1 self.refresh_img() def show_message(self): if len(self.qlabel.rectangle_label) > 0: reply = QMessageBox.question(self, '确认', '当前有未保存信息,是否继续?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return self.qlabel.rectangle_label.clear() if os.path.isfile(self.folder_path + '/' + self.img_name_list[self.current_img_index - 1] + '.csv') == False: QMessageBox.information(self, 'warning', '当前图片无信息') return message = pd.read_csv(self.folder_path + '/' + self.img_name_list[self.current_img_index - 1] + '.csv', sep=',', header=None) message = np.array(message.T) message = message.astype(int) for i in range(len(message)): self.qlabel.rectangle_label.append( Rectangle(message[i][1], message[i][2], message[i][3], message[i][4], True, message[i][0])) self.update_list() self.refresh_img() QMessageBox.information(self, 'complete', '信息加载完毕') def open_folder(self): self.folder_path = self.img_folder_text.text() if os.path.isdir(self.folder_path) == False: QMessageBox.information(self, 'warning', '文件夹路径非法') return self.img_list.clear() self.img_name_list.clear() for file_name in os.listdir(self.folder_path + '/'): img = cv2.imread(self.folder_path + '/' + file_name) if img is None: continue self.img_list.append(img) self.img_name_list.append(os.path.splitext(file_name)[0]) QMessageBox.information(self, 'complete', '图片加载完毕') self.total_img_number = len(self.img_list) self.current_img_index = 1 self.refresh_img() def goto_chosen_img(self): if self.jump_img_text.text().isdigit() == False: QMessageBox.information(self, 'warning', '请输入合法的数字') return if int(self.jump_img_text.text()) <= 0 or int( self.jump_img_text.text()) > self.total_img_number: QMessageBox.information(self, 'warning', '请输入合法的数字') return self.current_img_index = int(self.jump_img_text.text()) self.refresh_img() def refresh_img(self): img = self.img_list[self.current_img_index - 1] self.qlabel.img = img.copy() self.qlabel.update_qlabel_img() self.qlabel.update_img() self.show_index_message.setText('一共' + str(self.total_img_number) + '张图片,当前第' + str(self.current_img_index) + '张图片') def label_on_activated(self): self.label = self.label_combo.currentIndex() def update_list(self): slm = QStringListModel() string_list = [] for i in range(len(self.qlabel.rectangle_label)): string_list.append( LABEL_LIST[self.qlabel.rectangle_label[i].label]) slm.setStringList(string_list) self.listview.setModel(slm) def list_clicked(self, qModelIndex): if self.qlabel.rectangle_label[ qModelIndex.row()].whether_display == True: self.qlabel.rectangle_label[ qModelIndex.row()].whether_display = False else: self.qlabel.rectangle_label[ qModelIndex.row()].whether_display = True self.qlabel.update_qlabel_img() self.qlabel.update_img() def save_current_border(self): self.qlabel.save_current_border(self.label) self.qlabel.update_qlabel_img() self.qlabel.update_img() self.update_list() def label_clicked(self): sender = self.sender() if sender == self.label_button: self.label = self.label_button.checkedId() def save_message(self): if self.save_current_angle() == False: return self.qlabel.rectangle_label.clear() self.update_list() self.refresh_img() def save_current_angle(self): save_data = [] for i in range(5): save_data.append([]) if len(self.qlabel.rectangle_label) > 0: if os.path.isfile(self.folder_path + '/' + self.img_name_list[self.current_img_index - 1] + '.csv'): reply = QMessageBox.question(self, '确认', '是否覆盖当前图片已保存信息?', QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.No: return False for i in range(len(self.qlabel.rectangle_label)): save_data[0].append(self.qlabel.rectangle_label[i].label) save_data[1].append(self.qlabel.rectangle_label[i].x0) save_data[2].append(self.qlabel.rectangle_label[i].x1) save_data[3].append(self.qlabel.rectangle_label[i].y0) save_data[4].append(self.qlabel.rectangle_label[i].y1) if os.path.exists('crop_img/') == False: os.makedirs('crop_img/') h, w, channel = self.qlabel.img.shape img_after_crop = self.qlabel.img[ self.qlabel.rectangle_label[i].y0 * h // self.qlabel. qlabel_width:self.qlabel.rectangle_label[i].y1 * h // self.qlabel.qlabel_width, self.qlabel.rectangle_label[i].x0 * w // self.qlabel. qlabel_length:self.qlabel.rectangle_label[i].x1 * w // self.qlabel.qlabel_length] if self.whether_to_crop == 1: cv2.imwrite( 'crop_img/' + self.img_name_list[self.current_img_index - 1] + '_' + str(i) + '.jpg', img_after_crop) if np.shape(np.array(save_data)) != (5, 0): np.savetxt(self.folder_path + '/' + self.img_name_list[self.current_img_index - 1] + '.csv', np.array(save_data), delimiter=',') def delete_border(self): if self.listview.currentIndex().row() > -1: self.qlabel.delete_border(self.listview.currentIndex().row()) self.qlabel.update_qlabel_img() self.qlabel.update_img() self.update_list() else: QMessageBox.information(self, 'warning', '请先选中一行')
class DesktopIconWidget(QFrame): def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.Box | QFrame.Sunken) self.setStyleSheet("QListView{background:transparent;}") self.listView = QListView(self) self.setLayout(QHBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.listView) self.listView.setContextMenuPolicy(Qt.CustomContextMenu) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listView.setMovement(QListView.Snap) self.listView.setFlow(QListView.LeftToRight) self.listView.setResizeMode(QListView.Adjust) self.listView.setGridSize(QSize(self.logicalDpiX() / 96 * 70, self.logicalDpiY() / 96 * 70)) self.listView.setViewMode(QListView.IconMode) self.quickDesktopModel = QuickDesktopModel(self.window().platform.databaseFile) self.listView.setModel(self.quickDesktopModel) self.createActions() self.makeConnections() def createActions(self): self.actionCreateComputer = QAction(self.tr("我的电脑(&C)"), self) self.actionCreateDocuments = QAction(self.tr("我的文档(&D)"), self) self.actionCreateMusic = QAction(self.tr("我的音乐(&M)"), self) self.actionCreatePictures = QAction(self.tr("我的图片(&P)"), self) self.actionCreateShortcut = QAction(self.tr("创建快捷方式(&C)"), self) self.actionCreateShortcut.setIcon(QIcon(":/images/new.png")) self.actionCreateBookmark = QAction(self.tr("创建网络链接(&B)"), self) self.actionCreateBookmark.setIcon(QIcon(":/images/insert-link.png")) self.actionRemoveShortcut = QAction(self.tr("删除快捷方式(&R)"), self) self.actionRemoveShortcut.setIcon(QIcon(":/images/delete.png")) self.actionRenameShortcut = QAction(self.tr("重命名(&N)"), self) self.actionRenameShortcut.setIcon(QIcon(":/images/edit-rename.png")) self.actionEditShortcut = QAction(self.tr("编辑快捷方式(&E)"), self) self.actionEditShortcut.setIcon(QIcon(":/images/edit.png")) def makeConnections(self): self.listView.customContextMenuRequested.connect(self.onQuickDesktopContextMenuRequest) self.listView.activated.connect(self.runQuickDesktopShortcut) self.actionCreateComputer.triggered.connect(self.createComputerShortcut) self.actionCreateDocuments.triggered.connect(self.createDocumentsShortcut) self.actionCreateMusic.triggered.connect(self.createMusicShortcut) self.actionCreatePictures.triggered.connect(self.createPicturesShortcut) self.actionCreateShortcut.triggered.connect(self.createShortcut) self.actionCreateBookmark.triggered.connect(self.createBookmark) self.actionEditShortcut.triggered.connect(self.editShortcut) self.actionRemoveShortcut.triggered.connect(self.removeShortcut) self.actionRenameShortcut.triggered.connect(self.renameShortcut) def onQuickDesktopContextMenuRequest(self, pos): index = self.listView.indexAt(pos) self.listView.setCurrentIndex(index) menu = QMenu() menu.addAction(self.actionCreateShortcut) menu.addAction(self.actionCreateBookmark) menu2 = menu.addMenu(self.tr("创建特殊快捷方式(&S)")) if os.name == "nt": menu2.addAction(self.actionCreateComputer) menu2.addAction(self.actionCreateDocuments) menu2.addAction(self.actionCreatePictures) menu2.addAction(self.actionCreateMusic) if index.isValid(): menu.addAction(self.actionRemoveShortcut) if not self.quickDesktopModel.isSpecialShortcut(index): menu.addAction(self.actionEditShortcut) menu.addAction(self.actionRenameShortcut) try: getattr(menu, "exec")(QCursor.pos()) except AttributeError: getattr(menu, "exec_")(QCursor.pos()) def createShortcut(self): d = ShortcutDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = d.getResult() shortcut["id"] = str(uuid.uuid4()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createBookmark(self): d = BookmarkDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = { "id": str(uuid.uuid4()), "icon": "", "openwith": "", "dir": "", } shortcut.update(d.getResult()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createComputerShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的电脑"), "path": COMPUTER_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createDocumentsShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的文档"), "path": DOCUMENTS_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createPicturesShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("图片收藏"), "path": PICTURES_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createMusicShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的音乐"), "path": MUSIC_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def renameShortcut(self): self.listView.edit(self.listView.currentIndex()) def removeShortcut(self): self.quickDesktopModel.removeShortcut(self.listView.currentIndex()) def editShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return shortcut = self.quickDesktopModel.shortcutAt(index) url = QUrl.fromUserInput(shortcut["path"]) if not url.isValid(): return if url.scheme() == "special": QMessageBox.information(self, self.tr("编辑快捷方式"), self.tr("不能编辑特殊图标。")) return elif url.scheme() == "file": d = ShortcutDialog(self) else: d = BookmarkDialog(self) if self.window().runDialog(d.edit, shortcut) == QDialog.Accepted: shortcut.update(d.getResult()) self.quickDesktopModel.updateShortcut(shortcut, index) d.deleteLater() def runQuickDesktopShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return if not self.quickDesktopModel.runShortcut(index): QMessageBox.information(self, self.tr("快捷面板"), \ self.tr("不能运行快捷方式。请检查文件是否存在或者程序是否正确。")) else: self.window().close()