class View(WFrame): ## 조회할 기사 # @var Article article = None ## 생성자 def __init__(self, master=None, article=None, **kw): self.article = article super().__init__(master, **kw) def initializeWidget(self): self.scrollFrame = VScrollWidget(self) self.scrollFrame.pack(fill=BOTH, expand=TRUE) self.lblArticle = Label(self.scrollFrame.frame) self.lblArticle['justify'] = LEFT self.lblArticle['text'] = '\n'.join(self.article.texts) self.lblArticle['font'] = 'Consolas' self.lblArticle['padx'] = 0 self.lblArticle['pady'] = 0 self.lblArticle.pack(padx=(40, 0), pady=(20, 0), anchor=NW) self.text = '기사 보기' self.width = 640 self.height = 480 self.startPosition = StartPosition.centerParent
class Fixer(WFrame): typos = None def __init__(self, master=None, **kw): self.typos = Fixer.load() super().__init__(master, **kw) def initializeWidget(self): self.scrollFrame = VScrollWidget(self) self.scrollFrame.pack(fill=BOTH, expand=TRUE) for typo in self.typos: label = Label(self.scrollFrame.frame) label['justify'] = LEFT label['font'] = 'Consolas' label['padx'] = 0 label['pady'] = 0 label['text'] = typo.toString(Fixer.suggest(typo)) label.pack(padx=(40, 0), pady=(20, 0), anchor=NW) self.text = '오타 알리미' self.width = 640 self.height = 480 self.startPosition = StartPosition.centerParent ## 오타에 대한 조언을하는 메서드 # # 매우 중요! # @return string @staticmethod def suggest(typo): if ' ' in typo.context[typo.expected - 2:][:4]: return '차분한 마음으로 타자해보세요.' elif typo.ch in typo.context[typo.expected - 2:][:4]: return '타속은 너무 신경쓰지 말고,\n연습하는 느낌으로 타자해보세요.' return '좀 더 연습하세요.' @staticmethod def load(): typos = None try: with open('data/typos.pkl', 'rb') as data: typos = pickle.load(data) except: pass return TypoList() if typos == None else typos @staticmethod def save(typoList): typoBak = Fixer.load() with open('data/typos.pkl', 'wb') as typos: pickle.dump(typoBak + typoList, typos)
def initializeWidget(self): self.txtKeyword = Entry(self) self.txtKeyword['width'] = 987654 self.txtKeyword.grid(row=0, column=0) self.btnSearch = Button(self) self.btnSearch['text'] = '검색' self.btnSearch['command'] = self.search self.btnSearch.grid(row=0, column=1) self.frmArticleList = VScrollWidget(self) self.frmArticleList.grid(row=1, column=0, columnspan=2, sticky=N) self.frmArticleList.bind_all('<Button-1>', self.select) self.btnSearchNext = Button(self) self.btnSearchNext['text'] = '더 보기' self.btnSearchNext['command'] = self.searchNext self.btnSearchNext.grid(row=2, column=0, columnspan=2) self.text = 'NYTimes 기사 검색기' self.width = 400 self.height = 300 self.startPosition = StartPosition.centerParent self.columnconfigure(0, weight=1) self.rowconfigure(1, weight=1)
def initializeWidget(self): self.scrollFrame = VScrollWidget(self) self.scrollFrame.pack(fill=BOTH, expand=TRUE) self.lblArticle = Label(self.scrollFrame.frame) self.lblArticle['justify'] = LEFT self.lblArticle['text'] = '\n'.join(self.article.texts) self.lblArticle['font'] = 'Consolas' self.lblArticle['padx'] = 0 self.lblArticle['pady'] = 0 self.lblArticle.pack(padx=(40, 0), pady=(20, 0), anchor=NW) self.text = '기사 보기' self.width = 640 self.height = 480 self.startPosition = StartPosition.centerParent
def initializeWidget(self): self.scrollFrame = VScrollWidget(self) self.scrollFrame.pack(fill=BOTH, expand=TRUE) for typo in self.typos: label = Label(self.scrollFrame.frame) label['justify'] = LEFT label['font'] = 'Consolas' label['padx'] = 0 label['pady'] = 0 label['text'] = typo.toString(Fixer.suggest(typo)) label.pack(padx=(40, 0), pady=(20, 0), anchor=NW) self.text = '오타 알리미' self.width = 640 self.height = 480 self.startPosition = StartPosition.centerParent
class Search(WFrame): ## 검색 결과 선택한 Article # @see select() # @var Article result = None def initializeWidget(self): self.txtKeyword = Entry(self) self.txtKeyword['width'] = 987654 self.txtKeyword.grid(row=0, column=0) self.btnSearch = Button(self) self.btnSearch['text'] = '검색' self.btnSearch['command'] = self.search self.btnSearch.grid(row=0, column=1) self.frmArticleList = VScrollWidget(self) self.frmArticleList.grid(row=1, column=0, columnspan=2, sticky=N) self.frmArticleList.bind_all('<Button-1>', self.select) self.btnSearchNext = Button(self) self.btnSearchNext['text'] = '더 보기' self.btnSearchNext['command'] = self.searchNext self.btnSearchNext.grid(row=2, column=0, columnspan=2) self.text = 'NYTimes 기사 검색기' self.width = 400 self.height = 300 self.startPosition = StartPosition.centerParent self.columnconfigure(0, weight=1) self.rowconfigure(1, weight=1) ## 기사 검색에 필요한 초기화 작업을 한다. def search(self): for widget in self.frmArticleList.frame.winfo_children(): widget.destroy() self.page = 0 self.searchNext() ## txtKeyword의 값으로 기사를 검색하고 화면에 결과를 출력한다. def searchNext(self): self.page += 1 for article in Search.getArticles(self.txtKeyword.get(), self.page): ArticleWidget(self.frmArticleList.frame, article).pack() ## 선택한 ArticleWidget의 article을 load()하고 result에 저장 후 창을 닫는다. def select(self, e): isArticleWidget = isinstance(e.widget, ArticleWidget) if isArticleWidget or isinstance(e.widget.master, ArticleWidget): aw = e.widget if isArticleWidget else e.widget.master try: aw.article.load() self.result = aw.article self.close() except Exception as e: print(e) MessageBox.showerror(self.text, '기사를 불러오지 못했습니다.\n잠시 후 다시 시도하세요.') ## NYTimes의 API를 이용해 keyword에 해당하는 기사의 목록을 10개 단위로 가져온다. # # http://developer.nytimes.com/docs/read/article_search_api_v2 # @param keyword 검색할 키워드 # @param page 페이지 # @return list<Article> @staticmethod def getArticles(keyword, page=1): url = 'http://api.nytimes.com/svc/search/v2/articlesearch.json?api-key=%s&fl=%s&page=%d' % ( urllib.parse.quote(__config__.APIKey), urllib.parse.quote('web_url,headline,word_count'), (page - 1) * 10) if len(keyword) > 0: url += '&q=%s' % urllib.parse.quote(keyword) response = urllib.request.urlopen(url) content = response.read().decode('UTF-8') jobject = json.loads(content, 'UTF-8') articles = [] for i in jobject['response']['docs']: url = i['web_url'] # i['headline']['main']은 KeyError가 발생할 수 있음 title = i['headline'].get('main') words = i['word_count'] articles.append(Article(url, title, words)) return articles