debug心得(二)

~i:首先定位到的是double_clicked,然后是openfileordir,然后发现是拒绝访问但是没有异常抛出,当时在外层double_clicked,能够获取这个异常,在内层看log是setExcept函数缺少一个位置参数,然而我还在固执的认为是前面ldfs.getattr的问题.之后后来更改了setExcept函数问题解决.
~:debug的时候不能带太多的感情因素,不能固执的按自己的想法来。
~~:不能觉得自己认为怎么怎么样,要尊重log,机器几乎不会犯错。这回log已经告诉你了,你就不要不动脑子的固执了,这样没有任何意义,这也是思维的惰性。这种情况可以起来走走,然后按逻辑思维来,既然是setExcept的事,那么哪里调用except?在openfileordir中的哪里调用?外层能捕获异常,说明就在本函数内,那么为什么不认真的寻找一下?


~ii:登陆后注销再登陆,会有几率serversetting会出现空的时候,最开始时候的思路就是想着既然它没有被设置,那我们就设置一下,在注销信号中,重新的用数据库填充了一下,后来发现,这样是不行的,没有找到问题的根源。后来看了一下逻辑,login本质上一直是没有关闭的(资源),这次注销也只是重新显示罢了.然后就定位到了clicked_pblogin,这里

def on_pbLogin_clicked(self):
    if self.ip == "" and self.port == "":
        ip, port = self.setting.initServerSetting()
    else:
        ip = self.ip
        port = self.port
    if ip == "" or port == "":
        QMessageBox.critical(None,
                "错误", 
                "网络地址或端口未设置")
        self.on_tbLoginSetting_clicked()

刚开始的时候以为是setting被关闭了,所以不行,谁知这里的逻辑写的很奇怪,如果你是没有点开过setting,那么self.ip self.port自然为空,self.setting自然是没有被关闭,所以是上面第三行代码,要是打开过,就是第4,5行代码。最下面用的也是ip,port 当时天真的以为就是上面,其实什么都没有看,(在定位到逻辑代码的时候一定要判断是在上面还是在下面,为什么这么写,这么设置)这里这么干就是区分有没有点开。我当时就范了这种直觉上的错误,没思考就以为是上面的。然后就反复在这里折腾,开始以为是初始话的问题,然而根本没报错,打了log发现ip,port 为空也还以为是异常了,现在想想根本就不对,异常怎么可能会不抛出,在里面的时候也有问题,同样是逻辑上的惰性

def initServerSetting(self):
    try:
        self.cur.execute("SELECT ip,port FROM serversetting ORDER BY currlogintime DESC")
        ipPort = self.cur.fetchall()
        for i in ipPort:
            self.cbServer.addItem(i[0])
        self.cbServer.setCurrentText(ipPort[0][0])
        self.cbPort.setCurrentText(ipPort[0][1])
        #self.cbPort.setCurrentText(ipPort[1])
        self.cur.execute("SELECT port FROM serversetting WHERE ip='%s'" % ipPort[0][0])
        ports = self.cur.fetchall()
        for p in ports:
            self.cbPort.addItem(p[0])
        return ipPort[0][0], ipPort[0][1]
    except:
        return "", ""

~:这里明明在下面写了log 没有错误,为什么不看看上面呢,这中错误只能是两者中的其一,不是下面就是上面,debug的时候不能带感情的……,不能觉得自己怎么样就怎么样,尊重log,这种在已知中找未知,不能有个人感情(再次强调).是哪里就是哪里,不要过于懒惰执着。


~iii:main.py里面关于创建新的文件夹然后点击搜索栏的问题。昨天第一次看这段代码的时候,因为__createdir,__twfileRename,__closename等等变量的不清楚,而且函数来回嵌套,所以我又在来回的重复了的浪费了时间。最后的解决方法不是在来回看函数的时候猜解意思。而是用笔记,把相关的结构记下来,然后在依据变量在整个app中出现的位置来尝试理解它们的作用。
~:用笔记这个方法能在不了解结构的时候,分解结构,知道大概逻辑,因为笔记能把结构和变量记住,我个人的脑容量或这说内存还是太弱了。只能依靠辅助工具。
~~:大脑和身体在重复的时候,就该起来清醒一下,或者换一种方法了。


~iv:在fileshare的文件名中,开始以为是在左边的qglsearchfriend中加入了右边的listwidgetItem这里纠结了半天,看下去后发现这里是我犯蠢了,或者说根本就没有认真看,因为后面的那个只读和读写在additem中是隐藏的,但是因为我没有认真看的缘故,白白的浪费了很多的时间,其实看qt designer的时候就应该知道,Qstackwidget明明对应的就是两种widget在名字也暗示了,一个是搜索小伙伴,一个是(显示)小伙伴。只不过listwidget把搜索显示的item和右边选择好的结果的小伙伴的item复用了罢了。这里最大的问题就是我看到了一个ui文件的名称没有认真的联想,而且因为看的不仔细浪费了大量的时间。真是愚蠢而不自知,真是gg。


~v:这个是关于main页面点击头像,会调用userinfo.py,然后我在其中设置的 setToolTipText setLongText 函数没有生效,我当时用print排查到了其中 getuserinfo,知道是成功调用的,但是到了上面的两个函数却是失效的,当时不知道大脑是怎么想的,后来问了别人发现是其中的userpicture的问题,如实是null,就会直接的返回。
~:我犯的错误两点,首先,我之前花了大量的时间在print外面,以试图在外面寻求问题,不思考的反复的在外面print,这个跟之前一样,这样会浪费大量的时间,而来这么做根本不会得到正确的结果,当真是费力不讨好,真正解决问题的路就是要动脑子走的难走的路,而看似能给你心里安慰的路最后什么都剩不下。


~\~愚蠢的csdn,不能写文章,用qq暂时记录一下。~~
~vi:on_pbShareOk_clicked 对于这个函数,首先便确认了是for in 添加文件夹的分享,修改bug后发现鼠标的不正常,开始以为是卡主了,或者是ldmessagebox的问题,纠结了半天,后来发现也许是cursor的问题,搜索了一下,其实文档还是没有看懂,但是却看懂了文档中的例子,进而发现了msg点击确认以后的return导致没有重置cursor成功, 后来就很快的解决了问题。

~:确认问题的时候还是第一时间靠了直觉以为是加载或者msg的问题,这里用的经验而没有用心思考。至少没有列出选项,明明都看到了cursor却也没有太大的触动,(对英文不敏感,这个是一个很重要的问题)没有第一时间看看这是干什么的,搜索的整个py文件的时候看的也不认真(显示出了我一贯不求甚解的态度,以为会不影响大局,其实很多时候都影响了)。
~~:下回遇到问题,第一时间认真分析可能性,有几种可能,然后对每种可能性都开始验证,在这期间不能夹杂感情,要理性的debug。


vi:关于断网后新建文件夹成功,然后闪退的故事。首先定位到了文件choicefile,点击新建按钮,为pbNewFile func –> 在首行添加了一个row,然后self.twFile.setItem(0, 0, fileNameIndex)添加了一个新建文件夹,并且打开。然后到closeFileName,定位到了这里

result = self.choiceReadDir(self.dir)
if not result:
    #self.twFile.removeRow(0) 这句为解bug后加上
    return
self.setFile(self.dir)
self.createDir(rename)  ------>这里还有一个setfile 我认为没必要

choiceReadDir 会向服务器请求确认一下目录,异常会返回权限,是否存在文件夹,能否访问等信息。我开始以为是在这里捕获就可以了,但是不行。在这里浪费一些事件,然后看了createdir func –> 在这里又捕获了异常墨迹了很久,这个函数最后还是去用choice func 来确认了一下通过结果来判断 如果 result 为none就return ,否则就setFile(dir)来重绘tablewidget。最后读通了流程,知道先判断文件信息,如果有result,就可以新建 dir 然后setFile了。
~: 问题在于确认流程,这一套流程下来是怎么样的,pbNewFile –>新建插入一个正在编辑的item –>click 空白 –> closeFileName –> choicefile –> result –> 判断result if result –> createDir –> mkdir setFile –> success else: return 明白这个流程,就知道它们没有考虑断网的情况,所以我在return前添加了remove row即是。
~\~:kz让我看cancel和ok的崩溃,从cancel来看就是getrows的原因,debug一下知道是getstatus的问题,学习了一下hasattre method。我当时有点太着急有点点乱了方寸,ok也是差不多的套路。至于双击也是直接找相对应的slot 函数了。
~~~:学到的一点就是要对英文敏感,而且明确目标流程,流程不搞清楚是不行的,知道它明确的在哪里退出,找到bug真正产生的地方。
///:昨天我向解决这个bug的时候就是像屋头苍蝇一样,没有搞清楚流程,下回一定要搞清楚。然后通过二分来排查。
!:发现了一个奇怪的东西,貌似一个函数是一个整体,因为我设置了time.sleep 但是它还是没有分开显示而是一个函数执行好了才显示….这个不知道是怎么回事.


vii:关于下载更新后,点击安装的bug,下载好更新后,会弹出msgbox,询问是否安装更新,这里的代码是这样的。

if reply == QMessageBox.AcceptRole:
    newfilepath = homePath+os.sep+'newVersion'+os.sep+newmaxfilename
    newfilepath = newfilepath.replace('/','\\')
    newfilepath = newfilepath.replace('\\','\\\\')

    os.system(newfilepath)
    sys.exit()
    return

点击确认进入到这里后通过os.system执行了.exe文件安装包,安装包会检测当前的进程 是否有 xxx.exe ,如果有就终止,但这个地方应该是正常安装下去的。但是这个时候并没有退出这个线程,造成了bug。然后我在这里纠结了很长时间,长到甚至我都不知道自己这个下午到4点多都干了些什么。然后4点多开始杨总开始不耐烦的催我,并告诉我了测试方法 (我以为是没有explorer.exe 是不能检测代码的,因为进程名字不一样,一个是longdisc.exe,一个是python.exe,然后就是安装包是需要explorer.exe 这个被编译出来的文件的,其实是可以直接拿开发板测的,把nsis脚本改一下名字就好了。这我真的没有想到,甚至以为他说的太想当然了,因为没有explorer文件怎么测代码,这个时候脑子太不清楚了。) 在压力下,尝试寻找方法,知道是 os.system(newfilepath) sys.exit() 这两行代码,执行os.system后是等待的(阻塞的),没有立刻退出造成的问题。所以就要寻找非阻塞的方法。查找到了 subprocess 这个库,其中的popen是可以的。

subprocess.Popen(newfilepath,shell=True)

然后又遇到了些问题,不想去看官方文档,查了很多有的没的blog,然后就会提示你说需要 提升权限 winerror code:470 这样。然后又搜解决办法, 最后才发现是需要把 shell 设置成 true 就可以了。这个看介绍是说fork了一个子进程出来,这里我没理解这个子进程和父进程之间的关系, 父进程死掉了貌似子进程也不会受到影响 (貌似fork了就算是子进程了? 此处待续..),然后测试,通过。
~:其实最开始就意识到了是哪里的问题,但是就是不想再动os.system这段code了,然后就围绕着问题跑圈也不去解决它。浪费了大量的时间。感觉以前是没问题的,但是现在有问题了,一定是谁改了什么,这点不确定,印象中确实以前是好的,不过就算以前是好的,现在不好了也是需要解决的, 不能逃避
~\~:犯了之前的错误,遇到了不愿意看文档,其实看文档是最需要的,其他都是辅助,但是我还是选择去选择不动脑,这样反而浪费了大量的时间,而且不总结的话自己就算模模糊糊的意识到了,也不会有什么改变,记录是一种思考,但是记录后什么都不做,那么就是只是记录道,而没有体验道。这样还不如不记
~~~:意识到了进程这个东西是够阻塞的了,很耽误事情。难怪gui需要开各种线程,否则这还真是一个麻烦的事情,sad。而且上面的一个原因还是心不够静,这样是不行的。
!:这个逃避的问题犯了太多次的错误,千万不要再犯了,否则就是太愚蠢了。


viii:昨天关于最大化最小化的问题,首先就是通过点击任务栏缩小然后点击托盘栏不能放大,我最最开始就意识到了其实是因为,通过任务栏点击和mian主窗口点击的不一样在于住窗口的设置 ismin/max _ _ maxmineted/ _ _minmineted 的设置问题,但是逃避掉了,想要弄清楚全部的原理,其实完全不必要(这个弄清楚所有看似是在努力,实际上是在逃避,其实大脑一开始就知道该怎么做是正确的,而其他的一些东西就只是辅助。),最后在反复看看 tb_close_click showInterface shownormal 等函数的时候,突然领悟到了,ismin/max __maxmineted __minmineted 的作用,这里又想到了我另一篇日志中领导跟我说的做之前自己想一遍,不要逃避。,知道了作用以后过了一下放大缩小的函数,然后直接定位到了active window func 接下来就是判断这个时候的状态,是正常显示还是放大显示 normal / max show.
~:这个弄清楚所有看似是在努力,实际上是在逃避,其实大脑一开始就知道该怎么做是正确的,而其他的一些东西就只是辅助。而且这个错误不是第一次犯了,今天也是(0310,明明知道应该看django,却想看算法和计算机网络,后两个是重要,但是我的内心知道,真正重要的django,唯一的优势就是我对web开发核心的东西有了了解。)
~~:时刻检查自己是否在重复的浪费时间。
~~\~:挨打要立正,努力工作,不要给他笑脸就是了,扑克脸嘛,我最擅长。你做你的,我做我的。


iv:今天突然要发版本,手忙脚乱,以往的压力简直不值一提,我发现了自己真实还很弱,首先的问题就是关于python字符串转义的事。

111
333

就是这样的字符串,同事让我检测, 看看能不能find到 \n 而我非常愚蠢的用 /n 来找,结果不用说,根本是找不到的。而且当时我还给str encode成了 bytes,结果还是没有发现,自己真实太蠢了,不过他让我测,我测了。他没有问我为什么没测到,也说自己全部测过了。说明根本不在乎我因为什么未完成,只在乎结果,所以,我更要自己努力学习,别人是不会管你的。
~i:在于我的粗心 (这不是第一次了,因为粗心造成的错误,关于字符串,看书,关于字符,太多了,这样的错误不能再犯了。)
~~i:关于检测版本,我原来用的是把 x.x.x.x 的版本号变成 xxxx的str => int 然后比较,这有个问题就是xxxx 如果其中有一位是两位数,那么就不能了,因为不能分辨,我的解决办法就是,split 用doc分开,然后遍历的去比较。
说名最开始考虑的并不周全,应该好好考虑的。


v:关于分享文件消息后,在/mnt/datapools/xxx/中没有写入日志文件的bug,yang跟我说,让我联系谢,他是做服务器的,他问我说分享文件有没有带上session_id,我当时的第一反应是找yang去问有没有带session_id,他当时笑着看向我问我你看有没有带,我说那我看一下。然后我开始尝试试图分析整个上传文件的过程,从代码中写流程图,但是没写多少就意识到了这是一个不对的方向,太浪费时间而且未必能解决问题。于是变成了从 log 开始分析,这里意识到了log的重要性,如果没有log,这个bug对我而言是非常难解的,,从log的try call (func) 中确认发送本地文件首先 创建本地数据库创建任务,然后给远程一个创建一个文件 -> func(create),然后会进行上传,调用 func(upload) ,最后调用 putsharefile告诉发送此条分享文件的消息(~ ~这里是如何发送的?),一个调用了这三个函数,我并不确认谢说的是哪一个没有带session_id,但是我想,应该是最后一个,因为分享日志应该是成功了才会写进日志中,我观察了前两个函数,没有session-id参数,而且在最后一个putsharefile中发现了session-id,不过却为0,我开始也是信号整数最大值的问题,后来发现根本不是,因为session-id不是通过信号触发到finishupload中的,而是本身的self.session.id。于是我开始观察参数,发现给了5个参数,而两处调用 (i:上传文件,ii:聊天中上传文件) 发现后者比前者少了一个issafebox,但是func中后几个都是默认none导致没有报错,并且根据位置参数把他赋值到了前一个参数issafebox中而session-id变成了None,到这里我就添加上了相应变量传进去,problem over。
~:没有任何一个问题是别人的问题,尤其是在这个 explorer 的项目上,我当时还是下意识的以为这个问题可以交给他来解决,认为他能记得住,如果他说算了,我来弄,我又会觉得不爽,机会是要自己把握住的,我意识到了分解这个东西是费劲的,所以下意识的逃避了,不要逃避,要尝试去解决,每一个遇到的感觉棘手的挑战都是认识自己的好机会,要迎难而上,要冷漠,要仔细,要加油。
~~:解bug未必需要你多懂其中的东西,定位到问题所在,根据log来找到相应的地方,加上一些合理的分析,来排除bug,想到知乎上新fllow的一位知友的关于如何背思想政治的文章,提到,你只需要知道思想政治这个它究竟想要表达什么,它所表达的东西是一套模式的,就像一个人说的思想,然而信不信是另外一回事。回归到这个解bug的问题上,如果只是解bug 不需要知道完全的东西,只需要知道,在相应的时候(模式)做什么相应的反应(解bug的姿势)就可以了(kevin也说过类似的话,猜测bug产生的原因,看上下文解决bug),本质上是parttern match。至于整个系统源码的阅读,那就是另外一回事了,
~~\~:上一条写完后我意识到,都源码不是画流程图这么简单,需要的是其中的逻辑驱动,什么线程干了什么,在首先画完的流程图上要再简化一次,比如这个上传下载发送消息这个,什么线程驱动什么,任务线程,现在上传线程,聊天的db,线程前后的状态更新。其中的逻辑的关联才是重要的。


vi:当点击一个chatlfile时候,鼠标没有reset,定位到imgview,

if os.path.isfile(file):
    if self.format.lower() == "gif":
        mov = QMovie(file)
        self.img = mov
        self.giffile = file
        self.view.setMovie(self.img)
        self.img.start()
        self.updateImage()
        QApplication.restoreOverrideCursor()
    else:
        img = QImage()
        img.load(file)
        self.img = QPixmap.fromImage(img)

        self.updateImage()
        QApplication.restoreOverrideCursor()

发现没有处理文件不存在的情况,把reset拿出来解决,同事说加上msgbox提示,在用singal传参数的时候给chatLitem时候报错,提示chatRitem缺少参数,晚上6点,下班回家,回家后继续思考,没有结果,每个item都绑定了filetransfer 中的 downloader uploader,downloader,我晚上以为是有分辨的方法,没想到是暴力传输,这样messagebox出现那种没有文字的情况就是说,多个msgbox重叠在一起了,说白了就是我对聊天这个信号和聊天系统的不了解。(这个bug我的细节我记的不是很清楚了,以后还是要今日事今日毕)


vii:关于在chatlfileitem点击转存后,如果之前实在回收站,那么点击就是没有生效,我开始发现是回收站和前几个文件都不太一样,根本没有文件的地址栏,就想跳转不过去是不是因为没有地址栏的缘故,然后去看点击recycle bin button后 发现leaddresstext设置成了 recycle ,又看到lfileitem中的跳转最后是如下写的,

LDFSWINDOW.window.twMainMenu.setCurrentIndex(0)
# LDFSWINDOW.window.setSwInterFace(0)
LDFSWINDOW.window.on_pbRefresh_clicked(filepath)

所以在 pbrefresh func 最开是判断了 leaddress.text() 然后如果是recycle的话,就调用 on_pbmyfile_click func. 这里code review的时候被同事批评了,说如果不是我的文件里的文件呢?我以为要通过path来判断,yang说,不是没有跳转过去,而是没有翻页,所以要把上面#号注释掉的地方加上,我是意识到了它们的不一样,但是没有意识到翻页的问题,(其实我看 on pbrefresh cl 的时候,没有意识到它跳转成功了,看来对这段的东西还是不了解,文件访问刷新button这些)添加上注释那句,问题解决。
~:为什么没意识到翻页的问题这是个问题,需要在思考,问题就出在这里,待续…


viii:这个问题和上个问题是有些关联的,如果在回收站或我的共享勾选了tablewidget item,点击前面的button 文件 myfile group file 等等,delete button 没有变为不可用,但是在前面的 button 是勾选了 item 是可以重置的,我当时总结了3个问题,

  • 在不同button下,如何重置了delete buttton 设置为了false?
  • 相同的button下,同样重置了 deletebutton
  • recycle pb 为何与其他的 pb 不一样?

第一个问题,我 view myfile click func –> update(dir) –> (第一次到这里就没有看settwfile了,因为觉得settwfile里,没有设置delete pb的东西)setTWfile(dir.subfiles)
然后我查看了deletel pb .setenable(false) 在的几个地方,init,几个特定的tablewidget下的selectrow的变化,等等,还有getrows–> on_twFile_itemSelectionChanged(self),于是就卡在这里了,在这里突然被同事找去解决上面的那个问题,意识到这个也有可能是没有翻页的问题,stackwidget,于是在翻页的函数 setSWinterface的时候,在切换index的时候加上了set delete.setenabled false,至此问题解决。开始复盘
~:犯了几个错误,从定位setenabled false的时候,就应该 —> 定位到是getrow() —> set twfile item… 然后log 进行测试,但是更多的还是跟随直觉,并没有尊重事实, ,在这里推导出是 twfile item变化导致重置(然而这里没有重置,说明twfile item selection 没有变化,要在这里注意到是selection,即是选择 勾选 会调用函数,),然后bug是回收站勾选,delete pb 为可用,但是点击到 myfile click 没有导致之前函数的变化(twfile item selection),要意识到,是勾选item 没有变化,所以没有引发函数,虽然都会set twfile or lwfile 但是 如果item 本身选择初始是没有勾选的,那么其他地方点击就不会触发item change -> getrow -> set delete false 。
这个click myfile 等pb的时候,是先切换了 swinterface,所以我在setcurrentindex的时候设置了set enabled false,完成重置。以前没有问题是因为 这个状态机 初始值一定是 0 在没有变化的时候就是0 不可点击,勾选后就是1 在按其他button的时候,或这这个按钮的时候,item变化导致重置,但是如果最开始时在回收站导致了值为1的话,无论怎么点item是空 非勾选,还是不会初始化,为false,
后来我又发现即使用set weinterface setcurrentindex 的时候加上false 也会出问题,这个地方在于我对整个ui的不熟悉,对twfile swfile 的结构不清楚,swfile是stackwidget翻页,是右边最大的widget(swinterface这个大widget)下的关于tablewidget的stack widget (里面有 twfile wid lwfile wid safebox wid share /friend wid)每个widget下面都是一个tablewid,而twfile 只是下面我的文件等几个button后的 tablewidget,它的item形成了一个闭环,如果这个delete的状态还要维护的话,两点,第一点,在swfile翻页的时候,重设delete pb,第二点就是在settwfile setlwfile的时候重置。
所以最开始的在swinterface的设置就没用了,这里我采用的第二点的方法,至此问题解决。
~~: 所有的一切都要有输出,输出才是最重要的,只有这个才是i重要的,一切的一切就是这样。


ix:功能,发送的图片文件提供转存功能,yang已经写好了按钮样式,需要我做的就是把功能实现,说是缺少shareid,我当时想法是去看文件存储的时候做了什么,发现要把 filename 和 shareid传进去,所以需要的是shareid,于是定位到是在 file 上传成功后,transfer thread 发送一个 signal 到 fileitem. —> finish upload 在其中调用了
result = LDFS.putsharefile(filename, dstpath, checksum, sid=self.session.sid)
然后把 shareid 存储在 msg的content的这个字典中'{"shareid":%s,"filename":"%s","size":%s}',然后文件转存的时候获取这个msg对象的content属性即可。我想到把shareid存储到 img base64的标签中,在这里我浪费了一些时间,不知道该怎么用属性存储[1],最后放在了 width 后面,接下来就是在imageview的转存函数中取出这个值,然后放进choicefileUI中,然后在根据能改名字等等做一些小的修改,over。不过我遇到了一些困难,比如 如果是发送截图的话,就可以发送多个,这种情况下用 taskid 与msg.taskid 相等的判断,在一个图片可以,多个就会出现误判,所以我想的方法也跟遍历差不多,就是用md5来find这个msg.content找到就在这个index 下find name 找到就return 找不到就加上,因为md5 是确定的,有重复的也就没有关系了。跟yang沟通发现说可以在imageview种做,因为能拿到 md5 就是文件名 然后remote path 也可以拼出来,sessionid也能通过 msg获取到,所以尝试了一下,over。
~:[1] 纠结没有意义,因为如果找不到哪个是正确的,不如试一下,有这个时间什么都有了,—> 不要逃避自己的内心,犹豫不决的时候,把想法写下来,按照逻辑走,不要考虑自己的心情。
~~:yang说的,你需要的只是shareid,这个是最主要的,remotepath,sessionid则是可以获取的,所以是可以不存储的。——> 我的错误在于看到可用的代码 finish upload 就想着在这个上面改,并没有在思考,没有考虑我要达到的目的是什么(需要shareid)所以导致除了问题,如果连目标都没有岂不是瞎乱转,—-> 不是不知道目标而是目标在潜意识中,应该写在纸面上比较好。就今天这个情况,如果能写出来目标,然后在此基础上认真考虑,也许情况会好一些。这个就要等到下回再试了。


x:搞清楚整个下载的logic概况了,我最最开始接触项目的时候,尝试过用穷举遍历法,一点点的用眼睛看去理清逻辑,然后突然有一天意识到可以用纸笔来记的,然后发现记录的太过繁琐了,太乱了,迷失在了细节中,尤其是对写的不是那么清晰的代码。最近再看的时候就本着不在意细节,在自己思考这段逻辑怎么样做的基础上,理清真正的逻辑,要分清主次,比如我看filetransfer 要的就是理清 两点,
i:与db的交互,创建task后 save,然后各种状态改变,upload doanload时save(写到这里我发现我对这里与db交互还是没有完全了解。)
ii:与rest层的接口的call,什么时候创建远程path(call create),什么时候上传(call upload),这个我已经搞清楚了。
然后我的笔记改了好几遍,力求简洁完整。
首先别的地方call fileup/download –> create task(uploadtask/downtask) –> task.save()–> db.save() insert-db get taskid,变成task的属性。然后通过TransferFileManager的各种暂停,等待,正在task list的check,manager里面不保存特定的task,每个操作都是通过传如的task参数调用task本身的方法(thread 也为task的一个属性了),保存了一些 transfer list。
task.dostart:

  • task.prepare(准备 check一些条件)
  • task.check(无MD5就计算赋值,(create func(建立远程目录)) md5)
  • task.transfer(while handle –> 分块上传,计算每个块的md5,直到最后一块结束)
    最后 finish work 发送 siganl 到 r/l item

这里写一点关联的东西,在R/L/fileItem里,经常有task.id 和msg.taskid 判断相等的问题,msg obj从服务器paser 后是taskid 为0,只有通过点击up/download的时候 –> 到filetransfer —> create task –> task.save() get task.id (这里task对象的id传递给了msg msg.save()) finish up/download的时候 emit 时通过 args 传递到 chat item中。就可以与msg.task.id进行比较了。简单来说就是在task建立后id 给msg 然后thread 传输后拿这个id与msg.task的id相比较即可。


xi:拖动图片和文件一起到textedit中,遍历调用 send loacl file,然后提示
connect() failed between DlgChatRFileItem.sigChangePicture[] and updatePicture()
++++++++++++ wrapped C/C++ object of type DlgChat has been deleted
判断出两点第一就是以为是信号发送的时候失败了,另一点就是整个页面被刷新了。
我根据第一点开始搜索,说是被自动gc了,然后觉得应该是emit 了 signal 但是没有接收到的原因(这个其实非常蠢,因为那个signal是改变头像的,但是头像根本没有改变啊),然后就纠结究竟是哪里的问题,在chat file中浪费了不少时间打log 发现insert msg被多次调用,然后强行无视, 到这里我就转向的第二点就是觉得嗯,应该是insert的时候刷新了整个界面(我以为是被动刷新—->这里又是我愚蠢了),所以觉得chat dialog 是新生成的,才会显示dlgchat是被删掉了。然后同事这个时候跟我说,搞清楚是哪里刷新回收掉的??定位到问题所在,在这个压力下我开始怀疑是主动刷新,然后发现果不其然,init是被调用过的,这里多次调用insert msg也是因为重新初始化的缘故,到了这里就胶着了,期间同事问我看的怎么样了,我就说是还是insert的时候界面刷新,现在想来这个回答真是十分的愚蠢,后来我开始看main就是发送到服务器后接受到parse后的msg消息,在疯狂的打log,自以为是的以为是最后面通过checkmesssage进行save 然后insert msg转到chat中的逻辑来,在打log的过程中忽视了一些情况,真是非常之愚蠢,然后后来发现根本没有执行到这里,于是我就开始耐心的打log,发现在是自己发送的消息时,msg.userid = lxxs.user.id 时,如果执行到这里改变msg的send status 然后就save msg 执行reload 重新重构了chat页面,完成了刷新,在这里我就想,那下面的通过checkmessage还有什么意义,于是就直接注释掉了,问题解决。
~:

  • 犯了几个愚蠢的老生常谈的错误,其中就有自己的主观判断,而不能推导出事实依据,比如以为是被动刷新的,排除主动刷新,为啥不能是主动刷新?
  • 看到还有不懂的逻辑的地方为啥不去继续看,还在这里纠结舒适区,这个愚蠢+1。
  • 以为一定执行到了checkmessage func 愚蠢+2,为啥不打log,打了log还不相信,愚蠢+3。

~~:跟《原则》里说的,指选择对自己最有利的方法,比如水费的这个问题,要选择最有效的方法。才行。


xii:@功能的实现,之后在服务器拉取 sessionMsg的时候代码如下

if XXMessage.isChatMsg(msg['type']):
    # 这里ldmsg chat retract 这里我最开始写错了
    if XXMessage.minorType(msg['type']) > XXMessage.LDMSG_CHAT_RETRACT:
        continue
if XXMessage.isSysMsg(msg['type']):
    if XXMessage.minorType(msg['type']) > XXMessage.LDMSG_NOTICE_SAFEBOX_PASSWORD:
        continue
if msg['uid'] != LDFS.user.uid:
    status = MessageStatus.recv
else:
    status = MessageStatus.sent
msg = XXMessage(session, msg['clientid'], msg['uid'],
                       msg['sendtime'], msg['content'], msg['type'],
                       msg['msgid'], status, 0, 0)
# TypeError: 'XXMessage' object is not subscriptable
# if msg['type'] == xxmessage.chat_at:
if msg.isChatAt():
    session.haveAtUnread = True
allmsg.append(msg)

在第一个注释的地方我发现报错了,就修改了相应写错的地方,后来再报错就是关于msg[‘tpye’]的错误问题,之后遇到了报错,如第二个注释所示,报错误sbuscriptable,我以为是还是msg[‘type’]写错了,但是发现没有写错,然后就想着明明是msg这个dict的问题,为啥会变成 xxmessage 这个类的问题,然后在这里墨迹墨迹了半天,后来突然意识到,这里把msg这个dict变成了一个session.msg的class,所以这里不应该用字典的方式,直接dot attr msg.type 即可完成操作。
~:错了问题明明已经定位到了具体行,但是缺固执己见,以为msg就是msg对console的提示视而不见,明明已经显示了这是一个msg的类了,愚蠢。
~:如果要使用相同的变量名,那就要意识到或者自己清楚自己在干什么才行。否则就会造成今天的情况。
~:不带感情的debug,像机器一样思考。


xiii:关于@的2.0版本,因为只给了我两天的时间,所以感觉很紧张很不知道该怎么做,但好歹是最周五之前做了出来,一路过来遇到了几个问题,记录之,之前y说了要做成微信的样子,然后又问在中文情况下不识别该怎么办?我当时有点想说我也不知道该怎么解决,但是看他看着我,感觉就是这个东西交给我来做,我就应该负责搞定它,于是我说那我来想办法[1],然后我花了周三一整天来想怎么获取到@这个字符在lineedit上,首先在keypressevent上肯定是获取不到的,无论是组合键还是@键,后来在这篇博文里找到了inputmethod这个event,

else if(QEvent::InputMethod== ev->type())
{
//中文输入法状态下
QInputMethodEvent *keyEvent = dynamic_cast<QInputMethodEvent *>(ev); 
QString strInput = keyEvent->commitString();
//此时的strInput就是键盘上按键
}
return true;
}

然后type=inpurtemothod真的能捕捉到,以为用strinput就可以了,以为把 ‘@’ 放在conmitstring函数中就可以自己处理了,return就行了,也没有仔细的看这个函数是干嘛的[2],然后又回过头的浪费时间,星期四早上又开始看这个函数,inputmethodevent的commitstr是你将要插入或者替换到textedit的文本,就是输入法选择出来的结果,到了这里我就意识到该如何做,就是计算坐标展示atwidget,然后发现@符号不能被表达出来,发现这个event被我return掉了,于是注释掉,这样就可以打出@符号,然后显示list,在插入的时候在删除@符号,跟微信一样,接下来就是源于如何显示一个listwidget,先参考了lwemotion和sessionlist,然后尝试画一个widget出来,当我话一个item和lwitem的时候发现它并没有显示出来,不知道为什么,周四晚上回家,调整大小后发现是大小问题,同时碰到了一个算是最大的一个问题,就是点击选择后,或者失去焦点消失后会重启整个程序,发现setparent就不会,然后多次尝试下,发现setparent后不是没有显示widget,而是距离太远看不到,第二天到公司,非常的紧张,已经意识到了是global mapto的问题,这里menu pop 用的maotoglobal( cursorrect.right.bottom),来获取了全局坐标,看了mapto 函数和 用了mapto的tbemotion,也看了文档[3],尝试写下了 mapto(self,xxbottom)为tmpPoint,然后setparent发现可用。然后想到关于close的问题,就用了grouplist和tbemotion的方法设置了一个是否存在的属性,在textedit依照我的想法判断keypressevent,但是这我两个判断@只有一个写了_atwidget[4],所以我一度以为英文情况下不好用,然后继续攻城略地,在中文调通的情况下,能识别上下,所以不会设置焦点,上下的时候setcurrentitem,然后在判断enter后 widget是否存在,这样回车可以选择click,然后插入,这里都解决了,后来的问题是想在textedit变化的时候,如果存在atwidget就关闭掉,因为不能显示多个widget,但是设置后才发现不好使,因为 imeEvent 这个先然后 text change 所以要判断是不是第一次显示,是的话就设置成false,否则的就会直接关掉,于是这里解决,然后意识到设置_atwidget需要在中英文处都进行设置,然后设置,最后调整 不到5个就设置长度和坐标,到了就滚动条,默认选择最后一个为currentitem。
~~~>> move() mapto qpoint(0,0) 然后还有对全局的把控,和对情况的判断和了解, 最重要的,关系数据之间的联系,最函数的了解,最基础的函数,没有看过doc也是不行的。要有重新意识的过程,这个很重要刷新认知,比如 thread的run()函数,那个线程结束的bug很轻易的找到,就是因为后来我读了run() doc 知道run结束即退出,所以接触循环即可,这里不懂move后面的东西就引不出来了,而且setparent 才能让move有效,这个也是要注意的。明天要修改 filter event 到 tesend上 还有小于5个的时候怎么写。


xiv: 关于更新版本后的数据库更新问题,还有qimage(url,format)的问题 todo(yang 你一定要清楚你每一步都在干什么,这里就是以为qimage的定义和参数的不了解所导致的问题。)
#待续。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值