def createTopBorder(self, w, h): topBorder = QLabel(self) topBorder.resize(w, h) btnSize = config("gui.topBorderBtnSize") narrowBtn = QPushButton(topBorder) narrowBtn.setObjectName("topBorderNarrowBtn") narrowBtn.clicked.connect(self.showMinimized) amplificationBtn = QPushButton(topBorder) amplificationBtn.setObjectName("topBorderAmplificationBtn") amplificationBtn.clicked.connect(self.amplification) closeBtn = QPushButton(topBorder) closeBtn.setObjectName("topBorderCloseBtn") closeBtn.clicked.connect(self.close) btns = (narrowBtn, amplificationBtn, closeBtn) margin = config("gui.topBorderBtnMargin") marginRight = config("gui.topBorderBtnMarginRight") x = w - len(btns) * (btnSize[0] + margin) + margin - marginRight y = config("gui.topBorderBtnMarginTop") for btn in btns: btn.move(x, y) x += margin + btnSize[0] return topBorder
def __init__(self, parent, size): super().__init__(parent) self.resize(*size) leftW = int(size[0] * config("gui.formWeightPercentage")) bottomTitle = QLabel("@魔方管家", self) bottomTitle.resize(leftW, 30) bottomTitle.move(0, 10) bottomTitle.setAlignment(Qt.AlignCenter) bottomTitle.setObjectName("bottomTitle") bottomSmallTitle = QLabel("文件智能管理工具", self) bottomSmallTitle.resize(leftW, 20) bottomSmallTitle.move(0, 30) bottomSmallTitle.setAlignment(Qt.AlignCenter) bottomSmallTitle.setObjectName("bottomSmallTitle") checkUpdateSize = config("gui.checkUpdateSize") CW, CH = checkUpdateSize[0], checkUpdateSize[1] checkUpdate = QLabel("检查更新", self) checkUpdate.setAlignment(Qt.AlignCenter) checkUpdate.resize(*checkUpdateSize) checkUpdate.move(leftW + int((size[0] - CW - leftW) / 2), int((size[1] - CH) / 2)) checkUpdate.setObjectName("checkUpdate")
def setSelected(self, selected): if selected: self.setStyleSheet(""" background-color:#8095ba; color:#abb6cb; """) self.setStyleSheet( config("gui.menuItemFocusStyle").format(self.id)) else: self.setStyleSheet(""" background-color:#96add4; color:#abb6cb; """) self.setStyleSheet(config("gui.menuItemStyle").format(self.id))
def triggerResultPanel(self): self.topBar.show() self.resultPanel.show() self.formPanel.hide() self.dropBar.move( self.resultPanel.size().width() + config("gui.dropBarLeftMargin"), self.topbarH) self.dropBar.setStatus(False)
def __init__(self): super().__init__() # 初始化窗口 windowSize = config('gui.windowSize') self.resize(*windowSize) self.center() self.setWindowFlags(Qt.FramelessWindowHint) self.setWindowTitle(config('gui.windowTitle')) # 初始化是否最大化 self.isNormal = True leftSideW = int(windowSize[0] * config('gui.leftSidePercentage')) logoRectH = int(config('gui.logoRectHeightPercentage') * windowSize[1]) logoRect = QLabel(self) logoRect.setObjectName("logoBox") logoRect.resize(leftSideW, logoRectH) menu = MainMenu(self, (leftSideW, windowSize[1] - logoRectH)) menu.move(0, logoRectH) mainW = windowSize[0] - leftSideW x = leftSideW y = 0 topBorderH = config('gui.topBorderHeight') topBorder = self.createTopBorder(mainW, topBorderH) topBorder.move(leftSideW, 0) y += topBorderH mainContentH = config('gui.mainContentHeight') mainContent = MainContent(self, (mainW, mainContentH), config('gui.defaultTab')) mainContent.move(x, y) y += mainContentH bottomBar = BottomBar(self, (mainW, config("gui.bottomBarHeight"))) bottomBar.move(x, y) bottomBar.setObjectName("bottomBar") # vbox = QVBoxLayout() # self.setLayout(vbox) # # vbox.addWidget(TopBar(self)) # vbox.addWidget(MainContent(self,'index')) # vbox.addWidget(BottomBar(self)) self.setObjectName("mainWindow") self.setStyleSheet(config('globalStyleSheet')) self.show()
def createTypeGroup(self): types = config('search.types') typeExtensions = config('search.typeExtensions') fs = [] for id in types: self.checkedType.setdefault(id, False) def setStated(state): self.checkedType[id] = state == Qt.Checked name = "{0}({1}{2})".format( types[id], ", ".join(["." + item for item in typeExtensions[id][:3]]), "..." if len(typeExtensions) > 3 else "") cb = QCheckBox(name, self) cb.stateChanged.connect(setStated) fs.append(FormItem(cb, lambda: self.checkedType[id], id)) return fs
def __init__(self, parent, name, id, defaultTab=None): super().__init__(name, parent) self.setAlignment(Qt.AlignCenter) self.id = id self.selected = False if id == config('gui.defaultTab'): self.selected = True self.setSelected(True) self.tabId = id if defaultTab is None else defaultTab
def run(self, path, k): immatrix, imgList = self.getFeatureImmatrix(path) V = self.getV(immatrix, len(imgList)) kmeans_model = KMeans(n_clusters=k) code = kmeans_model.fit_predict(V) cacheDir = getThumbCacheDir("imageCluster") thumbSize = config("search.similarSearchThumbSize") for img, classify in zip(imgList, code): print("{0} is class {1}".format(img, classify))
def __init__(self, parent, size): super().__init__(parent) self.resize(*size) lineW, btnW = config("gui.topBarSearchLineWidth"), config( "gui.topBarSearchBtnWidth") H = config("gui.topBarSearchHeight") x = int(size[0] * config("gui.formWeightPercentage") - lineW - btnW) y = (size[1] - H) // 4 searchEdit = QLabel(self) searchEdit.setObjectName("topBarSearchLine") searchEdit.resize(lineW, H) searchEdit.move(x, y) x += lineW btn = QPushButton(self) btn.setObjectName("topBarSearchBtn") btn.resize(btnW, H) btn.move(x, y)
def createCacheLimit(self): cb = QCheckBox("是否开启缓存", self) cacheLimit = QLineEdit(self) unit = QComboBox(self) self.addItemsFromData( unit, dict([(item, item) for item in config("search.units")])) return (FormItem(cb, getVal=cb.isChecked, id="onCache"), FormItem(QLabel("最大缓存空间", self)), FormItem(cacheLimit, getVal=cacheLimit.text, id="cacheLimit"), FormItem(unit, getVal=unit.currentData, id="cacheLimitUnit"))
def __init__(self, p, size): thumbSize = config("search.similarSearchThumbSize") super().__init__(p, size,[ Field("action", "操作", hasValue=False, delegateClass=ActionDelegate), Field("predict", "智能分类", formatMethod=self.getClassifyName), Field("thumb", "缩略图", defaultSize=thumbSize[0], delegateClass=ThumbDelegate, delegateParameters=(thumbSize,)), ],closeFields=["updatedTime","accessTime"]) self.classifyName = None self.className = None self.classDirs = None
def createFormAndResult(self, FormConstructor, ResultConstructor): # 获得尺寸 size = self.size() w, h = size.width(), size.height() # 初始化拖动条尺寸 dropW = config("gui.dropBarWidth") dropLeftMargin = config("gui.dropBarLeftMargin") # 创建头部搜索框 topbarH = config('gui.topBarHeight') topbar = TopBar(self, (w, topbarH)) topbar.show() # 创建表单面板 formW = int(w * config("gui.formWeightPercentage")) formPanel = FormConstructor(self) formPanel.resize(formW, h - topbarH) formPanel.move(0, topbarH) formPanel.show() # 创建结果面板 resultSize = (w - dropW - dropLeftMargin, h) resultPanel = ResultConstructor(self, resultSize) resultPanel.resize(*resultSize) resultPanel.hide() # 创建拖动条 dropBar = DropBar(self, onForm=True) dropBar.resize(dropW, h - topbarH) dropBar.move(formW, topbarH) dropBar.show() # 赋予成员变量 self.topBar = topbar self.formPanel = formPanel self.resultPanel = resultPanel self.dropBar = dropBar self.topbarH = topbarH
def search(self, compareObj, searchRoot, scoreLimit, quantityLimit): cacheDir = getThumbCacheDir("similar") thumbSize = config("search.similarSearchThumbSize") imglist = [] for root, dirs, files in os.walk(searchRoot, topdown=False): for file in files: ext = file[file.rfind(".") + 1:].lower() if ext not in exts: continue completePath = os.path.join(root, file) imglist.append([completePath, None]) targetFeature = self.getFeature(compareObj) fitImgList = [] targetFeatureSum = np.sum(targetFeature) for item in imglist: score = int( (1 - math.sqrt(sum( (self.getFeature(item[0]) - targetFeature)**2)) / targetFeatureSum) * 100) if score >= scoreLimit: fitImgList.append((item[0], score)) compareResults = sorted(fitImgList, key=lambda item: item[1], reverse=True)[:quantityLimit] results = [] i = 0 for item in compareResults: result = {} for field in self.fieldGetter: result[field] = self.fieldGetter[field](item[0]) completePath = item[0] s = completePath.rfind("/") result["similarPercentage"] = "{0}%".format(item[1]) result["fileName"] = completePath[s + 1:] result["path"] = completePath[:s] thumbPath = os.path.join(cacheDir, "{0}.jpg".format(i)) result["thumb"] = thumbPath results.append(result) im = Image.open(completePath) im.thumbnail(thumbSize) im.save(thumbPath, "JPEG") i += 1 return results
def changeTab(self, tabId): if self.active is not None: print("hide {0}".format(self.active.id)) self.active.hide() w, h = self.size().width(), self.size().height() - config("gui.mainContentTabMarginBottom") self.tabs.setdefault(tabId, self.constructors[tabId](self, QSize(w, h))) current = self.tabs[tabId] current.show() self.active = current print("show {0}".format(tabId)) if tabId in self.idMenuMap: tabId = self.idMenuMap[tabId] eventSystem.dispatch("selectedMenu", tabId)
def createSizeFilter(self): units = dict([(item, item) for item in config("search.units")]) minSizeVal = QLineEdit(self) minSizeUnit = QComboBox(self) self.addItemsFromData(minSizeUnit, units) maxSizeVal = QLineEdit(self) maxSizeUnit = QComboBox(self) self.addItemsFromData(maxSizeUnit, units) return (FormItem(QLabel("从", self)), FormItem(minSizeVal, minSizeVal.text, "minVal"), FormItem(minSizeUnit, minSizeUnit.currentData, "minUnit"), FormItem(QLabel("到", self)), FormItem(maxSizeVal, maxSizeVal.text, "maxVal"), FormItem(maxSizeUnit, maxSizeUnit.currentData, "maxUnit"))
def __init__(self, p, size): thumbSize = config("search.similarSearchThumbSize") super().__init__(p, size, [ Field("action", "操作", hasValue=False, delegateClass=ActionDelegate), Field("thumb", "缩略图", defaultSize=thumbSize[0], delegateClass=ThumbDelegate, delegateParameters=(thumbSize, )), Field("similarPercentage", "相似度") ], closeFields=["updatedTime", "accessTime"]) eventSystem.listen("finishedSimilarImageSearch", self.getResults, self) self.setObjectName("similarImageSearchResult") self.tableView.verticalHeader().setDefaultSectionSize(thumbSize[1])
def getSearcher(self): searcher = FileSearcher() rawData = self.getForm() keywords = rawData["keywords"] if keywords["keywords"] != "": formatKeywords = [] for item in keywords["keywords"].split(","): if item == "": continue formatKeywords.append(item) searcher.setKeywordFilter(formatKeywords, containAll=keywords["method"] == 1) fileSize = rawData["fileSize"] min, max = self.unitFormat(fileSize["minVal"], fileSize["minUnit"]), self.unitFormat( fileSize["maxVal"], fileSize["maxUnit"]) if min is not None or max is not None: searcher.setFileSizeFilter(min=min, max=max) for fun, field in zip( (searcher.setCreatedTimeFilter, searcher.setUpdatedTimeFilter, searcher.setAccessTimeFilter), ("created", "updated", "access")): data = rawData[field + "Date"] fromTime, toTime = self.QdateConvertoTime( data["from"]), self.QdateConvertoTime(data["to"]) if fromTime is not None or toTime is not None: fun(start=fromTime, end=toTime) typeExtensions = config("search.typeExtensions") extensions = set() fileType = rawData["fileType"] for type in fileType: if fileType[type] == True: for item in typeExtensions[type]: extensions.add(item) if rawData["fileExtension"] != "": for item in rawData["fileExtension"].split(","): if item == "": continue if item[0] == ".": item = item[1:] extensions.add(item.lower()) if len(extensions) > 0: searcher.setExtensionFilter(extensions) searcher.setPath(rawData["root"]) return searcher
def classify(self, categoriedDirs, classifyDir): X = [] y = [] for i,category in enumerate(categoriedDirs): for root, dirs, files in os.walk(category, topdown=False): for file in files: ext = file[file.rfind(".") + 1:].lower() if ext not in exts: continue completePath = os.path.join(root, file) X.append(self.getFeature(completePath)) y.append(i) X = np.array(X) y = np.array(y) k = len(y) // len(categoriedDirs) cacheDir = getThumbCacheDir("imageClassify") thumbSize = config("search.similarSearchThumbSize") results = [] for root, dirs, files in os.walk(classifyDir, topdown=False): for i,file in enumerate(files): ext = file[file.rfind(".") + 1:].lower() if ext not in exts: continue completePath = os.path.join(root, file) f = np.array(self.getFeature(completePath)) distances = np.sum((f - X) ** 2, axis=1) ys = distances.argsort()[:k] # w = np.zeros(len(categoriedDirs)) # for j in ys: # w[y[j]] += self.gaussian(distances[j]) # ans = w.argmax() ans = np.bincount(y[ys]).argmax() thumbPath = os.path.join(cacheDir, "{0}.jpg".format(i)) im = Image.open(completePath) im.thumbnail(thumbSize) im.save(thumbPath, "JPEG") file = self.buildData(completePath) file["predict"] = ans file["thumb"] = thumbPath results.append(file) return results
def run(self, path, k): immatrix, imgList = self.getFeatureImmatrix(path) V = self.getV(immatrix, len(imgList)) centroids, distortion, features = self.cluster(V, k) code, distance = self.getClusterResult(features, centroids) cacheDir = getThumbCacheDir("imageCluster") thumbSize = config("search.similarSearchThumbSize") result = [] i = 0 for img, classify in zip(imgList, code): file = self.buildData(img) thumbPath = os.path.join(cacheDir, "{0}.jpg".format(i)) file["thumb"] = thumbPath file["predict"] = classify im = Image.open(img) im.thumbnail(thumbSize) im.save(thumbPath, "JPEG") result.append(file) i += 1 return sorted(result, key=lambda x: x["predict"])
def search(self, compareObj, searchRoot, limit=10): cacheDir = getThumbCacheDir("similar") thumbSize = config("search.similarSearchThumbSize") imglist = [] for root, dirs, files in os.walk(searchRoot, topdown=False): for file in files: ext = file[file.rfind(".") + 1:].lower() if ext not in exts: continue completePath = os.path.join(root,file) imglist.append([completePath, None]) targetFeature = self.getFeature(compareObj) for item in imglist: item[1] = harris.match_twosided(targetFeature, self.getFeature(item[0])) compareResults = sorted(imglist,key=lambda item: item[1])[:limit] # # results = [] # i = 0 # targetFeatureSum = np.sum(targetFeature) # for item in compareResults: # result = {} # for field in self.fieldGetter: # result[field] = self.fieldGetter[field](item[0]) # completePath = item[0] # s = completePath.rfind("/") # result["similarPercentage"] = "{0}%".format(int((1 - math.sqrt(item[1]) / targetFeatureSum) * 100)) # result["fileName"] = completePath[s + 1:] # result["path"] = completePath[:s] # thumbPath = os.path.join(cacheDir, "{0}.jpg".format(i)) # result["thumb"] = thumbPath # results.append(result) # # # im = Image.open(completePath) # im.thumbnail(thumbSize) # im.save(thumbPath, "JPEG") # i += 1 return compareResults
def initUI(self, size): menuData = ( ('文件搜索', 'search', "normalSearch"), ('重复文件检测', 'repeatDetect'), ('文件整理', 'classify', 'textClassify'), ('系统设置', 'setting'), ) menus = [] w, h = size[0], size[1] / len(menuData) y = 0 for menu in menuData: item = MenuItem(self, *menu) item.resize(w, h) item.setStyleSheet(config("gui.menuItemStyle").format(menu[1])) item.setObjectName("menuItem") item.setFrameRect(QRect(0, 100, w, 30)) item.move(0, y) y += h menus.append(item) self.menus = menus eventSystem.listen("selectedMenu", self.selectedMenu, self)
class AbstractFormPanel(QLabel): units = config("search.units") def __init__(self, p: MainContentTab): super().__init__(p) self.form = {} self.worker = None self.searching = False self.grid: QGridLayout = None def initUI(self, formTitle, topMargin=0, bottomMargin=0): grid = QGridLayout() grid.setSpacing(10) grid.setContentsMargins(20, 0, 0, 0) self.grid = grid self.row = 0 self.setLayout(grid) self.grid.setContentsMargins(20, topMargin, 20, bottomMargin) formTitle = QLabel(formTitle, self) formTitle.setObjectName("formTitle") formTitle.setAlignment(Qt.AlignCenter) self.grid.addWidget(formTitle, self.row, 0, 1, 2) self.row += 1 self.createFieldGroup() self._createButtonGroup() def unitFormat(self, val, unit): if val == "": return None return int(val)**(AbstractFormPanel.units.index(unit) + 1) def QdateConvertoTime(self, date): if date == None: return None return time.mktime((date.year(), date.month(), date.day(), 0, 0, 0, date.dayOfWeek(), date.dayOfYear(), -1)) def createFieldGroup(self): pass def createGroup(self, builder, groupName, gorupId, col=None, *args): self.form.setdefault(gorupId, {}) label = QLabel(self) label.setObjectName("formLabel") label.setText(groupName + ":") label.setAlignment(Qt.AlignRight) self.grid.addWidget(label, self.row, 0) widgets = builder(*args) if col == None: col = sum([item.col for item in widgets ]) if type(widgets) == tuple else widgets.col grid = QGridLayout() c = 0 r = 0 if (type(widgets) == tuple or type(widgets) == list): maxRow = 1 for i in range(len(widgets)): item = widgets[i] if i > 0 and c % col == 0: c = 0 r += maxRow maxRow = 1 grid.addWidget(item.widget, r, c, item.row, item.col) if item.row > maxRow: maxRow = item.row c += item.col if item.getVal == None: continue if item.id == None: self.form[gorupId] = item else: self.form[gorupId][item.id] = item else: grid.addWidget(widgets.widget, 0, 1) self.form[gorupId] = widgets self.grid.addLayout(grid, self.row, 1) self.row += 1 def getForm(self): data = {} for key in self.form: if key == "buttons": continue row = self.form[key] if (type(row) == dict): group = {} for name in row: group[name] = row[name].getVal() else: group = row.getVal() data[key] = group for key in data: print("{0}:".format(key)) print(data[key]) return data def createRootDirctoryChoose(self, type="dirctory"): textEdit = QLineEdit(self) textEdit.setText(getUserRoot()) btn = QPushButton("浏览", self) btn.setObjectName("fileChooseBtn") btn.clicked.connect(self.getChooseRootDirctory(textEdit, type)) return (FormItem(textEdit, getVal=textEdit.text, col=1), FormItem(btn, col=4)) def getChooseRootDirctory(self, lineEdit, type): def event(): if type == "dirctory": fname = QFileDialog.getExistingDirectory( self, 'Open file', '/home') else: fname = QFileDialog.getOpenFileUrl(self, 'Open file', '/home')[0].path() print(fname) if fname == "": return lineEdit.setText(fname) return event def _createButtonGroup(self): HBox = QHBoxLayout() HBox.setSpacing(20) for btn in self.getBtns(): HBox.addWidget(btn) self.grid.addLayout(HBox, self.row, 0, 1, 2) def getBtns(self): return [] def addItemsFromData(self, combo, items): for key in items: combo.addItem(items[key], key)