数据可视化

excel提供了商业标准的可视化内容,但总显笨拙。也不希望excel形成垄断,到时候坐地起价。程序员的求知天性,也要求随心所欲得设计,总希望是设置参数而不是选项,是调用函数而不是下拉列表框。自由是要付出代价的,就像到地摊上淘A货,或者自已起炉灶。
总会用种种问题,不能显示中文,代码页不同,不能调整大小。众多的媒体推送,看着眼花缭乱。一看就会,一做就废。都成股市里的庄家,套路满满。听话就有糖吃的时代一去不复返。

  1. Matplotlib 默认情况不支持中文,我们可以使用以下简单的方法来解决。这里我们使用思源黑体,思源黑体是 Adobe 与 Google 推出的一款开源字体。
    官网:https://source.typekit.com/source-han-serif/cn/
    GitHub 地址:https://github.com/adobe-fonts/source-han-sans/tree/release/OTF/SimplifiedChinese
    2.很奇怪的代码。
    代码A:
  salary=pd.read_csv(u'data\\ch5\salary.csv',encoding = "gbk")
  andrews_curves(salary[['salary','begin_salary','jobtime','position']],'position')

代码B:

babaDf.plot(x=babaDf.index,y='Close')
plt.xlabel('时间')
plt.ylabel('股价(美元)')
plt.title('2019年阿里巴巴股价走势')
plt.grid(True)
plt.show()

代码A是正常理解的逻辑。andrews_curves函数传入数据参数。代码B中的Dataframe直接长一个".plot"。pandas内置了matplotlib?把matplotlib的绘图函数封装了。关键是能不能兼容进去,NO ZUO NO DIE,比如几个图作到一个图中去。
高手的思想惊人相似。引用知乎(五笔 tuhk)《python绘图-matplotlib.pyplot与pandas.plot()》一文中的话:
“注意事项:dataframe.plot()通过修改kind参数的值来改变绘图类型,matplotlib.pyplot使用不同的方法来改变绘图类型。”
https://zhuanlan.zhihu.com/p/108592028

closeDf.plot(kind='box')

3.如何把多张图作到一起
直接plot,就在一起了。神不神奇。利用subplot,可以起到分割屏幕布局的效果。plt.grid(True),可以设置网格,骨骼惊奇,出人意表。

ax1=googDf.plot(y='Close',label='谷歌')
amazDf.plot(ax=ax1,y='Close',label='亚马逊')
fbDf.plot(ax=ax1,y='Close',label='Facebook')
applDf.plot(ax=ax1,y='Close',label='苹果')
babaDf.plot(ax=ax1,y='Close',label='阿里巴巴')
txDf.plot(ax=ax1,y='Close_dollar',label='腾讯')
plt.xlabel('时间')
plt.ylabel('股价(美元)')
plt.title('2019年6家公司股价累计涨幅比较')
plt.grid(True)
plt.show()
ax2=plt.subplot(121)
googDf.plot(ax=ax2,y='Close',label='谷歌')
amazDf.plot(ax=ax2,y='Close',label='亚马逊')
plt.xlabel('时间')
plt.ylabel('股价(美元)')
plt.title('2019年2家公司股价累计涨幅比较')
plt.grid(True)
ax3=plt.subplot(122)
fbDf.plot(ax=ax3,y='Close',label='Facebook')
applDf.plot(ax=ax3,y='Close',label='苹果')
babaDf.plot(ax=ax3,y='Close',label='阿里巴巴')
txDf.plot(ax=ax3,y='Close_dollar',label='腾讯')
plt.xlabel('时间')
plt.title('2019年4家公司股价累计涨幅比较')
plt.grid(True)
plt.show()

import plotly.graph_objects as go
fig = go.Figure()
用fig.add_trace()也能实现布局切分。

4.gvim 到Notepad++,试试Jupyter Notebook。试试就试试,试试就掉沟里。

常规来说,安装了Anaconda发行版时已经自动为你安装了Jupyter Notebook的,但如果没有自动安装,那么就在终端(Linux或macOS的“终端”,Windows的“Anaconda Prompt”,以下均简称“终端”)中输入命令安装
anaconda对个人用户不收费bai,商业版du、zhi团队版、企业版需要收费。
google Colaboratory 提供免费的 GPU 计算服务!目前热门的AI项目基本都离不开GPU的计算,所以真心给力。

怎么感觉又是一个坑。现在已经掉到anaconda中去了。像不像网页的钓鱼连接。要看全部内容请注册之类的。关键看了两篇又臭又长的安装文章,还不知道什么是个头。感觉被抓去做安利了。
pip3 install jupyter
jupyter notebook
像启动重型轰炸机一样,启动了一个浏览器,然后一个自称简洁的界面,其实是然并卵的文件浏览器。别人家的集成运行,查看图表功能一样没有。后面要划重点,套路来了。
“此时你的界面当中应该还没有“Conda”和“Nbextensions”类目。不要着急,这两个类目将分别在“五、拓展功能”中的“1.关联Jupyter Notebook和conda的环境和包——‘nb_conda’”和“2.Markdown生成目录”中安装。”
想不装Conda,选Jupyter Notebook。结果选装功能的第一句就表示,Conda是必须的。而且Conda安装中包括了Jupyter Notebook,Jupyter Notebook我是Conda的三儿。Jupyter Notebook我是小弟,我全家都是小弟。不是全英文的就是高大上。
总体感觉是在玩helloKitty这个阶段,搞得很High,一到GUI程序就死翘翘。也就是一个红绿灯距离的热血沸腾。没整明白,拖那么大一家子,又是浏览器,又是mysql,又是widget的。瞧人家NotePad++,一二十兆大小。

5.选美。看谁最美。极品追求是达到matlab一样的科学幻境,又能photoshop一样满足好色之徒也追求.
Matplotlib 经常出现红配绿,赛狗屁的经典工科男风格。它的颜色可调,也有alhpa值,但没有谱。婴儿般的大红大绿。

6.实现大屏
背景图片是关键。这几乎不是一个数据计算的问题,而是一个美工的问题。找漂亮的背景图片为先。图片的主题,体现的科学知识背景。例如商务分的低饱和度主风格,加高饱和度的鲜艳对比色。
关键词:科技感 商务科技 抽象商务科技 互联网大数据 大数据科技 科技背景 电脑 概念表达 智能科技背景 未来智能 未来科技 智能科技 人工智能 大数据 互联网 大数据背景 蓝色科技 云计算 大数据新时代 科技背景 设计 现代科技 其他 300DPI JPG

7.布局实现。主要是实现合成的Figure,以及多个Figure能实现同时呈现。
方法一:用QT窗口的布局。可把学的QT用上了。
追求美的路上道阻且长。QtWebEngineWidgets.QWebEngineView()透明怎么弄?QT的WebEngine核心肯定也是泊来品。setStyleSheet(“background-color:transparent”)不行。像极了当年用系统消息折腾 windows窗口透明。记一下当淘到的软件vitrite。现代人都很现实了,不会这么去折腾。但还是很高兴在2017年的百度贴吧中找到了一个相关的论题,看到有人推荐了vitrite。本人很有感情的软件,怕人老了记不起来,特此留念。
CSDN中找到一个同样想法的人。还是高手,有福了。果然:

WebEngine只能对其page设置透明颜色,其他颜色透明度还不行:
webView->page()->setBackgroundColor(Qt::transparent);
https://blog.csdn.net/feiyangqingyun/article/details/88628376
方法二:想想show函数上能不能做点文章。
方法三:还有subplot这功能可以试试。
方法四:figure_factory看着样子像能干事。
			 plotly.figure_factory: helper methods for building specific complex charts

8.做到大屏化方面。plotly开始让人失望,或者这些都已经属于他们的收费项目,勾引进门后开始要被割韭菜。突然觉得Excel还算厚道。无论在背景设置,图形布局上商业化,可操作性强。plotly自定义性强,可编程性强,但到输出、布局、功能组合上就突然像断线了,好像设计者压根不准备向这方面发展。他们就提供个私人定制,你要稍微上点商业场景应用的成又聋又哑。有点像五笔打字,在输入单字二字词语上很强,但一到新词、网络语言方面就成老年痴呆。突然觉得OFFICE像用品牌的专家店,而这些野路子、标称个性化产品的却是像小商品市场里看人下菜的商贩。

9.Powerbi的数据可视化能力powerbi真的有种工科风,能力强悍但是颜值不高,可视化展现能力方面,PoweBI内置的图表种类相对较少,例如一些常用的玫瑰图、多层饼图、词云图、热力地图、流向地图等都不支持(需要进行市场图表拓展下载使用)。个人版免费。
10.finebi对个人免费,能够快速入手并且熟悉乃至精通。看这个图,比较符合个人的审美风格。
在这里插入图片描述

11.QT的splitter很好,但多个控件多层布局后的嵌套,让人崩溃。

12.把plotly搞成裸男的方法

			 plot_bgcolor='rgba(0,0,0,0)',#透明色,但不是这一块透明
             paper_bgcolor='rgba(0,0,0,0)',
             xaxis= {"gridcolor": "yellow","showgrid":False},
             yaxis= {"gridcolor": "yellow","showgrid":False},

13.上不了网,查不了API文档。解释性语言的魔力来一发。
#查看模块函数

print([e for e in dir(QtWebEngineWidgets.QWebEngineView) if (not e.startswith('_')) and ('set' in e) ])
print([e for e in dir(QtWidgets.QPushButton.__all__) if not e.startswith('_')])

14.QMdiSubWindow,结果两个窗口重叠时出现神奇现像。子窗口2上的widget浮大子窗口1上,而不是被子窗口1覆盖。嗨,诺基亚难怪要倒闭。应该是painter区域函数没有考虑覆盖的情况,只是考虑了子窗口平面不重叠的情况。难怪透明的悬浮窗口在浮动后就死活不能透明。毛病真是出在胎里了。
在这里插入图片描述
借用一段话,的确是QT娘胎里带来的毛病:

“windows下的透明是通过layered window实现的. Qt的透明窗口也是如此, 属于directui. 整个窗口只有一个winId(windows下即HWND). 
但是 opengl和directx都需要一个handle来绘制渲染. 
而Qt的窗口中, 如果某个子Widget获取了winid. 则打破"directui". 窗口中的所有widget都会拥有handle. 
因此透明窗口是无法单独把某个widget交给opengl或direcxt渲染的. ”

记得当初用VC6自带的工具能查看桌面程序每一个HWND。弄了半天现在这世道,能省则省了。似乎看到现在的电扇与几十年不坏、三大件时代的电扇。

QT没有封闭直接调用的函数,调用WIN32API还是逃不了,真是在Windows地盘,还是windows作主。世上从来没有救世主。

15.透明、多窗口重叠、异形窗口等,似乎到了GUI编程的深水区、软肋了。基于HTML又提到日程上来了。喜欢GUI的整体封装,但好像还是绕不开HTML。

16.微软的天坑简史。
微软的Windows用户界面开发从最初的基于C语言的Win32 API,到基于C++的MFC和基于C++模板的WTL,再到基于.NET和C#的WinForm以及WPF。
诸如Office这样的软件也没有使用MFC或者WTL。
WPF也不错,但是有时候需要使用C++来开发用户界面,MFC微软自己都不使用,WTL没有官方的维护。微软对于WTL也是一副后妈脸。
UWP微软内部开发的DirectUI框架。

17.其实做得漂亮些也不是很复杂,多用gradient和alphablend之类的函数就行了。gradient可以出磨砂效果,alphablend可以出半透明效果

17.找到PyQt5解决不透明的一个方案。
就这么简单,这么神奇。

把setAttribute(Qt::WA_TranslucentBackground);
放在self.show()的前面

但对QDockWidget还是没有卵用。估计真是QMainWindow与Widget基因不同,不同物种。
################################

C++构造函数原文:
{
        show();
	//设置无边界窗口并置顶
	setWindowFlags(/*Qt::CustomizeWindowHint|*/Qt::FramelessWindowHint |Qt::Tool);
	//窗口设置透明
	setAttribute(Qt::WA_TranslucentBackground,true);
	pen = QPen(Qt::red);
}
语句的顺序问题是C++的代码有误,还是PyQt5的原生问题。真想找C++去了,还是C++让人用得心安。PyQt5这种二道贩子,真不知道中间做了什么手脚。

18.QT天坑呀。在windows平台下,如果不把这个标题栏去掉,那么将不会是透明效果。
4.5版本发行以后,可以设置窗口属性Qt::WA_TranslucentBackground来设定该窗口透明显示,但是有一个问题,就是如果该窗口是个top level窗口,就会有标题栏(title bar), 在windows平台下,如果不把这个标题栏去掉(设置Qt::FramelessWindowHint 标志位就会去掉标题栏),那么将不会是透明效果,而是背景为全黑。

19.为毛画个矩形却只给显示一半,太欺负人了。

 def paintEvent(self,event):
        p=QPainter(self)
        p.setPen(self.pen)
        p.drawRect(QtCore.QRect(0,0,self.width(),self.height()))
        p.fillRect(QtCore.QRect(0, 0, 0, 0), QColor(0, 0, 100, 50) )

20.美数课代表,美数专家
在这里插入图片描述
在这里插入图片描述
21.color saturation :intensity of color hue
在这里插入图片描述
在这里插入图片描述
22.D3实现径向堆栈柱状图。得来全不费功夫。
在这里插入图片描述
23.D3实现力导向图在这里插入图片描述
24.年了几个Echart的大屏案例。还有D3.js。看来还是要皈依我佛–HTML。阿里云DataV看来是大咖。交互式、动画、3D将是比较的大项。

25.QPainter的画线看着舒心,比以前的win32API画的线好多了。也放地GDI+水平以上的抗锯齿,也可能是现在的屏幕比800*600的显示分辨率年代好太多。

26.继续作。QMovie无法半透明。没法让gif图片半透明

    self.movie1=loadGif()
    self.movie1.setWindowOpacity(0.5)
        
        
class loadGif(QWidget):
    def __init__(self):
        super().__init__()
        #self.setWindowTitle("装载GIF动画")
        #self.setFixedSize(512,288)
        self.setWindowFlags(Qt.Dialog|Qt.CustomizeWindowHint) #隐藏标题栏,窗口样式

        self.movie=QMovie("./futures/ani4.gif")  #加载本地动画文件GIF文件
        self.label=QLabel(self)
        self.label.setMovie(self.movie)
        self.label.setWindowOpacity(0.5)
        #self.movie.setWindowOpacity(0.5)
        self.movie.start()  #开启动画
	继续找原因。QtGUI,QtWidget不是一伙的。QtGUI是低层的存在。都是些QPainter、QBrush、QColor、QPen,像油漆工吃饭的家伙。没想到QMovie这样的高端货怎么也和他们是一伙的。
	The Qt GUI module provides classes for windowing system integration, event handling, OpenGL and OpenGL ES integration, 2D graphics, basic imaging, fonts and text. These classes are used internally by Qt's user interface technologies and can also be used directly, for instance to write applications using low-level OpenGL ES graphics APIs.

QT你就坑吧。以前还真是一家。问题是QLabel都去QtWidgets了,为毛QMovie还在QtGUI。

归根到底还是版本问题吧,提供的文档估计是版本qt4的,而我自己使用的是qt5,它两个之间的一个区别就是Qt5把关于控件的头文件都移到 <QtWidgets>中了,所以如果在 Qt5 中使用控件应该包含 <QtWidgets>而非<QtGui>

27.使用QWebEngineView控件时,为其指定了一个无边框、背景透明的父窗口,然后需要重绘QWebEngineView控件时,界面卡死,同时输出窗口打印出“UpdateLayeredWindowIndirect failed for ptDst=xxx”的错误。

28.还是用回了matplotlib.pyplot。与pandas结合紧。不要求美观的情况下,够用。而且不用外挂,show自己就能显示。
折腾字体吧。

plt.rcParams['font.sans-serif'] = ['SimHei'] # 步骤一(替换sans-serif字体)
plt.rcParams['axes.unicode_minus'] = False   # 步骤二(解决坐标轴负数的负号显示问题)

29.换matplotlib后,背景透明这事,又要一顿操作猛如虎。看来都是二百五。

30.人挡杀人,佛挡杀fo。暴该matplotlib源代码,实现透明及半透明。先用着。
backend_qt5.py文件,564行处插入下列代码。搞定。粗暴了。

print("564 FigureManagerQT backend_qt5.py 新加入解决窗口透明的问题")
self.window.setAttribute(Qt.WA_TranslucentBackground, True)
self.window.setWindowFlags(self.window.windowFlags()|Qt.SubWindow|Qt.FramelessWindowHint |Qt.Tool|Qt.WindowStaysOnTopHint)       
self.window.setWindowOpacity(0.6)

31.实现了figure.patch ,ax.patch透明,却出现了一个黄背景无法解决。不管了先暴改backend_qt5.py的class MainWindow。原来里面空空的,现在一个mainwindow应该有的体面总要给他加上。

class MainWindow(QtWidgets.QMainWindow):
    closing = QtCore.Signal()
    print("534 MainWindow backend_qt5.py 暴改了,为了实现无标题栏后的移动问题")
    #竟然没有init edit 2021/1/22
    #后面实例化中会覆盖这里的设置,故没有用
    def __init__(self):
        super().__init__()
        self.dragPosition=self.frameGeometry().topLeft()
        #self.setAttribute(Qt.WA_TranslucentBackground, True)        
        #print("524 backend_qt5.py")
        #self.setWindowFlags(self.windowFlags()|Qt.SubWindow|Qt.FramelessWindowHint |Qt.Tool|Qt.WindowStaysOnTopHint)       
    def keyPressEvent(self, event):

        if event.key() == Qt.Key_W and (event.modifiers() & Qt.ControlModifier):
            self.closing.emit()
            QtWidgets.QMainWindow.closeEvent(self, event)
    
    def mousePressEvent(self,event):
       # print(event.button())
        if (event.button() == Qt.LeftButton):
            self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()
            #print(self.dragPosition,type(self.dragPosition))
        
    def mouseMoveEvent(self,event):
        if (event.buttons() and Qt.LeftButton):
            self.move(event.globalPos() - self.dragPosition)
            event.accept()
            
    def closeEvent(self, event):
        self.closing.emit()
        QtWidgets.QMainWindow.closeEvent(self, event)

32.功夫不负有心人。终于实现matlabplotlib窗体透明。暴改FigureCanvasQT init() backend_qt5。使用QT窗体透明二大法之一,修改setPalette实现透明。

print("******250 FigureCanvasQT backend_qt5 自己加入的yellow,出了乌龙")
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.Background, QtGui.QColor(0x00,0xff,0x00,0x00)) 
#palette = QtGui.QPalette(QtCore.Qt.yellow)       
self.setPalette(palette)

33.Windows还是可移植。matlabplotlib源代码看得怀疑人生。为了实现一个简单的透明,这云山雾绕。特别是类工厂,看着很高级,实际却是反人类。
例如:DX是微软一家主导,开发,升级都是有明确目的的,而OpenGL想当老大的人太多,没家都要加自己的产品特性,导致OpenGL比同时代的DX性能弱(底层变的太多了)
第一感觉还是拿DX开刀。开源的项目看着高大上,哪一天生态做起来就开始收割韭菜,开始做商业运营了。看着像带头老大,实际却是吸免费劳动力。

34.用cl 编译链接,分分钟教做人。
用了几个小时,把人家的一段dx代码,修正了他的几个bug后终于生成exe。第一次用namespace当注释大段代码用。感觉用着挺顺手。
看到下面这种错误:

1>WinMain.obj : error LNK2019: unresolved external symbol __imp__DispatchMessageW@4 referenced in function _WinMain@16
2>WinMain.obj : error LNK2019: unresolved external symbol __imp__TranslateMessage@4 referenced in function _WinMain@16
3>WinMain.obj : error LNK2019: unresolved external symbol __imp__GetMessageW@16 referenced in function _WinMain@16
4>WinMain.obj : error LNK2019: unresolved external symbol __imp__UpdateWindow@4 referenced in function _WinMain@16
5>WinMain.obj : error LNK2019: unresolved external symbol __imp__ShowWindow@8 referenced in function _WinMain@16

解决方法。不问为什么,这么干就行。

#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")

在这里插入图片描述

35.用dx9实现了窗体留标题都可以透明。留下一个问题,移动、缩放时,自己的边框、背景会留在透明区域内。这也许就是QT必须把标题栏干翻才允许透明的原因吧。还有前面窗口的残留的问题。

在这里插入图片描述
在这里插入图片描述
36.图形世界总有一个高在上的Render,渲染。根源在哪里加入程序的过程,从窗口句柄建立开始,render出现在WM_PAINT消息中。原来如些。不说明白,这Render神秘得找不到北,以为又有什么神秘操作。
surface,就是一个二维数组。
In Direct3D, all two-dimensional (2D) images are represented by a linear range of memory called a surface. A surface can be thought of as a 2D array where each element holds a color value representing a small section of the image, called a pixel.

swap chain:
A swap chain is a series of buffers that “flip” to the screen one after another.
在这里插入图片描述

surface :
A surface represents a linear area of display memory and usually resides in the display memory of the display card, although surfaces can exist in system memory.
面,显存中表现的是连续的一块内存。为什么必须连续,如果显存渣到连一个面都存不下就别混了。所谓的点、线、面之中的面。中文常听,英语也知道face,surface有点高冷,直接说face对英语小学文化的人更亲近,或者直接说surface memory,更容易猜到什么东西。还有一个词,off-screen surface,看得慌得一B,这是什么东东。推测应该是非front buffer中的面,如back buffer、third buffer etc。
术语:Flipping surfaces. The process of moving the back buffer to the front buffer.

The GetRenderTargetData method provides a way to copy the contents of a render-target surface to a system-memory surface. 
默认的渲染目标叫做后备缓冲- 物理上就是包含下一帧要绘制的信息的一块显存。这句中文中的后备缓冲估计就是back buffer。也就是绕了一圈RenderTarget是back buffer换了一个马甲。的确是不认识。

RenderTarget:缓冲区,用来记录渲染后的输出的结果,而不直接将帧缓冲绘制到屏幕。为什么不直接在屏幕显了,一来显DX高级,二来主要是CPU好吃GPU的豆腐。

SetRenderTarget:
Setting a new render target will cause the viewport (see Viewports and Clipping (Direct3D 9)) to be set to the full size of the new render target.
viewport :a viewport is a two-dimensional (2D) rectangle into which a 3D scene is projected.
在这里插入图片描述

viewport ,视口。这翻译,眼里进沙子的感觉。翻译成2D视图、视角、视管、观察孔(管中窥豹),更好些。
我们关心的是,这事在哪里发生。如果没猜错,应该是在GPU中。

CreateDIBSection :

该函数提供一个指针,该指针指向位图位数据值的地方。可以给文件映射对象提供句柄,函数使用文件映射对象来创建位图,或者让系统为位图分配内存。
创建应用程序可以直接写入的、与设备无关的位图(DIB)的函数。
gdi32.lib中的函数。应该不属于dx。

CreateFileMapping :
属于Winbase.h,感觉应该是C语言中openfile的window版本原型。
查明是对Open打开的文件句柄的深加工。应该是为了保证文件内容的确读入实在的物理内存。

SelectObject:该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
gdi32.lib的说话方式。用婆婆的方式调教媳妇。

CreateCompatibleDC
该函数创建一个与指定设备兼容的内存设备上下文环境(DC)。通过GetDc()获取的HDC直接与相关设备沟通,而本函数创建的DC,则是与内存中的一个表面相关联。

如果没有辨析过surface概念,真不 知道这句话在说什么。也就是说,CreateCompatibleDC 是指向一块surface的指针,surface是一块连续的内存,这个可以整个交换到显存中。

world transformation :时空变换、时空切换。
world,世界,甚至就一个字“界”。界的具体意思,空间、时空。界,众生之界,而不是一个别的坐标。个人入众,众生之中的坐标。一人一世界,一界一众生。个人独一无二,只是在不同的界中的角色、坐标不同。
A world transform changes coordinates from model space, where vertices are defined relative to a model’s local origin, to World Space, where vertices are defined relative to an origin common to all the objects in a scene.
在这里插入图片描述

view matrix:视矩阵。摄像机视角。个人眼中能看到的图像,不是上帝视角。
The view matrix is the camera for the scene.

projection :投影,2D屏幕投影。如果有一天3D投影,这一步就可省了。
The projection transformation matrix defines how geometry is transformed from 3D view space to 2D viewport space.

ambient 周围的,氛围,气氛组。摆裙小组组,目前无人能cover。

meshes:网格。其他3D软件打包的模型。模型,几何型的组合。

DXUT即DirectX Utility Library,它是微软为DirectX Samples写的一个框架,有了这个框架,Sample的构建就方便多了,这个框架实际上抽取了构建Sample的公共代码bai,比如处理窗口消息,处理设备丢失与重设等等,将这些代码提取出来放到DXUT中,便于每个Sample重用。

37.顶点结构vertex
//--------------------------------------
// Desc:顶点结构
//--------------------------------------
struct CUSTOMVERTEX
{
FLOAT x,y,z;
FLOAT u,v;
};

x,y,z表示三维空间中的坐标,u,v表示纹理坐标,
关于纹理坐标,其实也是一个"平面",一个位于内存中的平面,它的U,V意味着,你将如何把纹理贴到平面上去,它们的顶点都是一样的,你可以拉伸或者变形等,

定义完顶点结构后,我们先放下它,再做一些其它的工作,我们是不是需要一个世界坐标呀?是不是还需要一个摄像机的坐标?以及摄像机的向上的向量来表示它是正立着还是倒立着?D3D给我们提供了这样一个结构来表示三维空间中唯一的点,D3DXVECTOR3,D3D还为我们提供了一个函数来建立这个坐标,D3DXMatrixLookAtLH,这个函数接受上述三个顶点,并且将创建好的左手迪卡尔坐标放在一个矩阵中,这个矩阵我们叫它观察矩阵,最后将这个观察矩阵交给D3D变换,最终输出到显示器上,实现3D效果;

左手迪卡尔坐标

38.VC++编译器,cl.exe /D UNICODE 选项会要求字符串前加L。
DXUTCreateWindow(L"BasicHLSL" );

#pragma comment ( lib,“wpcap.lib” )
表示链接wpcap.lib这个库。和在工程设置里写上链入wpcap.lib的效果一样(两种方式等价,或说一个隐式一个显式调用),不过这种方法写的 程序别人在使用你的代码的时候就不用再设置工程settings了。告诉连接器连接的时候要找ws2_32.lib,这样你就不用在linker的lib设置里指定这个lib了。
以前以为VC会到LIB目录下自动查找.lib文件。原来要把lib名字写好。只是不用写目录名。因为有LIB环境变量。LIB这个环境变量作用仅此而已。这也不难怪。有INCLUDE目录,还不是要也.h文件。虽然有点坑的感觉,感觉二道收费,房价是限制住了,绑定车位的价格上百万了,你说找谁说理去。

39.用cl编辑个BasicHLSL,被搞到半死。DXUT,恶心相当于当年的反人类的MFC。

40.AlphaBlend是Window自带的GDI函数,在用GUI的时候为了达到更漂亮的效果我们常常用它,它的参数之一的类型就是BLENDFUNCTION。

41.GetRenderTargetData,有没有可以写入RenderTarget的函数呢?
有IDirect3DDevice9::SetRenderTarget
还有一个ID3DXRenderToSurface类可以有点帮助。

1. 设置一个RenderTarget会导致viewport变成跟RenderTarget一样大

2. 反锯齿类型必须跟DepthStencilBuffer一样

3. RenderTarget的类型必须跟DepthStencilBuffer的类型兼容, 可以用IDirect3D9::CheckDepthStencilMatch进行检测

4. DepthStencilBuffer的大小必须>=RenderTarget的大小

5. IDirect3DDevice9::SetRenderTarget的第0个不能为NULL

6. Usage为D3DUSAGE_RENDERTARGET的Texture不能进行反锯齿, 而且Pool必须为D3DPOOL_DEFAULT. 如果想利用RenderTarget做为纹理又想反锯齿, 可以先把场景渲染到一个CreateRenderTarget创建的Surface(或BackBuffer), 再用IDirect3DDevice9::StretchRect拷贝到纹理上

7. D3DX提供了一个ID3DXRenderToSurface, 简化了RenderTarget的使用. 注意它的BeginScene跟EndScene与再用IDirect3DDevice9的同名函数对不能嵌套, 因为实际上内部还是调用的IDirect3DDevice9的, 用PIX可以看到它进行了哪些调用. 还有就是这个接口仍然不能反锯齿, 而且每次都要保存/恢复一堆状态, 总觉得不爽

8. RTT不能既做为输入就做为输出目标, 某些显卡上可能只会给一个warning, 有些显卡上则会发生报错/黑屏/死机之类不可预计的事情...另外, Depth stencil texture(参见Hareware shadow map)也有同样的问题, 用完之后要SetTexture(n, NULL)清空, 不然A卡会黑屏/花屏/深度错误, 既使你没有使用, 只要它被寄存器引用了, 显卡还是会当做是正在使用的, 这时就不能做为depth stencil buffer

9. RTT如果想保存到文件中, 是不能直接SaveToTexture的. 需要创建一个OffscreenSurface, 拷贝过去, 再保存. 不过N卡好像不支持DXT1格式的OffscreenSurface, 可以创建Texture, 取其level0的surface代替.

10. N卡在开启了锯齿后冒似所有的RTT都要反锯齿, 不然深度测试会失败-_-

11. Intel的显卡在RTT没有设置DepthBuffer时可能所有绘制全部深度测试失败, 需要关闭深度测试再画.

12. SRGBWRITE不支持Float格式的RT

13. MRT时使用第一个RT的alpha来做alpha test

14. MRT不支持反锯齿, 必须相同bitdepth, 可以不同格式, 必须相同大小

42.SetStreamSource
*设置资源流
SetFVF
*设置顶点格式

D3DFVF
Flexible Vertex Format Constants, or FVF codes, are used to describe the contents of vertices interleaved in a single data stream that will be processed by the fixed-function pipeline.

D3DFVF_DIFFUSE Vertex format includes a diffuse color component.
diffuse color:过渡色贴图,漫反射颜色

DrawPrimitive
所有计算机中复杂的图形都是用这几种点的渲染方式实现的,虽然简单但是很重要。通过这次的内容,我们理论上就能够把我们想显示的任何平面的图像都显示到D3D窗口里了。

43.可怜的C++字符串比较。这还不算,还有宽字符版本。这就是ZY的代价。

for(int i = 0; i < argCount; i++)
{
	if(wcscmp(szArgList[i],L"1")==0){
		bSWITCH=true;
		//MessageBox(NULL, L"bSWITCH", L"", MB_OK);
	}
	//MessageBox(NULL, szArgList[i], L"Arglist contents", MB_OK);
}

44.IDirect3DDevice9::Present
Presents the contents of the next buffer in the sequence of back buffers owned by the device.
其中Front buffer、back buffer分别被翻译成前台缓冲区、后台缓冲区。这前台、后台的叫法不错。

45.CS_OWNDC 这个 class style 让窗口管理器为该窗口创建一个 DC 并在对 BeginPaint 和 GetDC 的调用作出反应时使用该 DC。CS_CLASSDC 则更进一步,为属于该 class 的所有窗口创建同一个 DC。于是,上次我展示的那个由一个自认为对同一个窗口拥有两个的 DCs 的函数所引发的问题现在终于可以跨窗口地发作了。你觉得一个窗口有一个 DC,而另一个窗口有另一个 DC,可事实是它们是同一个东西。
CS_CLASSDC风格注册的窗口类,系统会为这个类分配一个窗口类DC。用这个窗口类创建的所有窗口,都共享这一个DC句柄。也就是说,这些窗口所使用的DC是公用的。

窗口是自己与系统合资的产品,不是随自己想怎么样就怎么样的。
窗口是Windows应用程序中非常重要的一个元素,一个Windows应用程序至少要有一个窗口,称为主窗口,窗口是我们看到的一块矩形区域,它是与用户进行交互的接口,利用窗口可以接受用户的输入以及对用户输入的响应。例如我们看到的QQ登陆界面就是一个窗口。窗口又可分为客户区和非客户区,如下图所示,其中,客户区通常用来显示控件或文字,标题栏、系统菜单,菜单栏、最小化框和最大化框、可调边框都称为窗口的非客户区,它们主要由Windows系统进行管理,我们创建的应用程序主要负责客户区的外观显示和操作,窗口也可以有一个父窗口,并且,对话框和消息框都是属于窗口。

//9.hbrBackground:背景画刷的句柄。为NULL
当hbrBackground为NULL时,应用程序必须在绘制客户区域时绘制它自己的背景。为了确定背景是否一定要绘制,应用程序或者可以处理 WM_ERASEBKGND消息,或者测试PAINTSTRUCT的fErase成员。PAINTSTRUCT是由BeginPaint函数填充的。

46.关于D3D中的BeginScene,EndScene及Present函数及可能的性能关系。
在D3D中,需要使用BeginScene和EndScene函数,然后所有的图元绘制代码才能被调用。通过了解,需要注意下下面一些问题:
1 BeginScene和EndScene必须成对实现。
2 BeginScene不能连续调用两次否则会出现调用异常。
3 EndScene属于作用是实际应用所有的绘制命令至显卡,但是它是异步执行的,即它会立即返回,但是不保证绘制命令执行完成。
4 Present函数会最终等待所有绘制命令结束并将结果从back buffer拷贝到front buffer。
5 BeginScene和EndScene之间的绘制代码量可以不要太多,当然太少也不好。这样才能保证最后的present不至于等待大量的CPU时间等显卡完成所有的绘制指令。这样可以在present之前多次使用BeginScene/EndScene队,保证CPU和GPU始终基本同时在工作(并行)。
6 如果确实存在BeginScene/EndScene之间绘制命令过多,可以在EndScene/Present之间添加一些CPU指令,避免CPU在Present时过多时间空等GPU完成绘制返回。

47.总体来说来是一种字节面向显卡,比如zhiOpenGl,Dx,一种使用操作系统提供的dao组件GDI,GDI+等
一般对于速度和效果要求不大的地方使用GDI系统就可以,GDI对硬件设备进行了封装,用户可以使用GDI结构来模拟硬件,具体的实现由操作系统完成,因为隔了一层虚拟机(操作系统),所以速度慢,但是画个窗体,字体,菜单,图片之类的是没有问题的
DirectDraw可以提供给开发者代表了真实显示内存的绘图页面。这意味着,只要你使用了DirectDraw,你就可以直接操纵显卡上的内存,图形显示变得出奇的快速。而且这些页面代表了显存中连续的内存块,使得在页面中寻址和读写变得非常方便。

首先这两个都过时了,特别是DirectDraw。
当年这两个都是用显卡加速的,区别最主要的是DirectDraw支持显存位图,GDI里位图只能在内存里,另外DirectDraw处理方式更贴近硬件,所以杂七杂八的事少,也就更快。Windows Vista开始GDI丧失显卡加速,虽然Win7又恢复了一点,但是还是没有往日荣光。DirectDraw这东西10年前就被Direct 3D掩埋了,DirectX 7开始D3D不再依赖DDraw,DirectX 8开始DDraw不再更新。

以前2D游戏区别于桌面应用主要在于有大量的位图复制操作,因为游戏里的内容都是事先生成好的位图,而桌面应用的内容往往是现画的。
GDI的硬件加速主要在画线、画圆、写字这些操作上,而画位图的时候,GDI的重大缺陷就是位图必须保存在内存里。虽然GDI画位图也是显卡加速的,但是位图数据必须通过速度相对来说很慢的前端总线传到显卡上。
而DDraw最核心的功能就是可以把位图直接保存在显存中,画位图的时候直接在显存中复制,通过带宽非常大的显卡内部总线。
比如你画一棵树,GDI每画一次就要从内存到显卡复制一次。而用DDraw之需要复制一次,以后都是在显存内操作了所以快。
但是于此同时DDraw舍弃了GDI的画线、画圆、写字乃至缩放位图等等的功能,所以渐渐被可以实现那些操作的D3D取代了。
GDI和DDraw都是会把显存映射到内存上的(事实上这个映射和GDI、DDraw这些东西没关系,是显卡驱动干的,所以32位系统不开PAE你装1G显存的显卡就会发现物理内存就无论如何也超不过3G了)
GDI只要不涉及位图的操作都是直接告诉显卡要画什么,CPU不会自己操作显存。但是如果是画位图,GDI就会通过CPU的内存操作把内存中的位图复制到显存里(可能也就是你理解的DDraw的行为)
而DDraw操作位图是直接告诉显卡把哪部分显存内容复制到显示区域,CPU不会自己操作显存。但是相应的DDraw只能操作位图。
GL和DX主要面向多媒体开发,比如视频播放和游戏,这些东西要求很好的显示效果,同时要能保证速度,比如视频至少的25fps,这要然GDI来画,你的电脑什么都不干都未必能完成,此时就要直接把数据送给显卡进行处理,并且充分利用显卡的处理和特效功能,这就是GL和Dx,DX叫Direct X其意义就是直接X.
gd和gdi有点类似把,不过差别还是比较大的,gd库最初只bai是gif draw,之后才开始更名为graphic draw,现在2.x支持的功能已经很强大,不过只限于网页绘图;gdi名为图形设备接口,最初微软是打算把它作为图形子系统,可惜对于窗体这种刷新率频繁的桌面系统来说,gdi的图形处理太慢了,所以才有了后来的directX系列,目前gdi主要的应用也还是出现在asp等页面上出个饼图,还有就是报表上出个图形什么的- -b

48.经过扩展后的结构体D3DXMATRIX和D3DXMATRIXA16对许多运算符进行了重载,所以可以直接进行转换运算、赋值运算以及多种一元、二元运算,大大方便了矩阵类型变量的运算。.

因为矩阵的运算相对比较复杂,所以Direct3D提供了一组矩阵运算函数,例如,
*这些矩阵有点像位图矩阵,无非这个是数学运算出来的。位图是从文件中读入的。

通过函数D3DXMatrixTranslation()构造一个平移矩阵;
通过函数D3DXMatrixRotationX()、D3DXMatrixRotationY()和D3DXMatrixRotationZ()构造绕x、y和z轴转动一定角度的矩阵;
通过函数D3DXMatrixScaling()构造一个缩放矩阵;
通过函数D3DXMatrxiIdentity()将一个矩阵单位化;
通过函数D3DXMatrixMultiply()计算两个矩阵的积;
通过函数D3DXMatrixInverse()求原矩阵的逆矩阵;
通过函数D3DXMatrixTranspose()计算原矩阵的转置矩阵。

49.Depth Buffers (Direct3D 9)

在这里插入图片描述
50.透明与效率是个悖论。
苦寻找透明的高效办法,特别想通过GPU直接实现,而不需要CPU参与的方法。目前还找不到理所当然的方法,显卡不就是把原来挡住的内容显示出来吗?就这么简易的事,显卡做起来那么难吗?如果所有窗口画面都存在显存里,显示的时候运算成一个显示平面,这有那么难吗?
从CPU到GPU分工时代,这个阶段未必能实现所有窗口显示信息都存显卡,否则cpu与GPU的数据通信将无比繁忙。GPU是仓库、CPU是主人,主人要最大限度自由支配所有资源,肯定不能把所有资源放在老远的地方。仓库方面也会因为主人的指令而疲于奔命,到头来GPU还会自己卡死不算,还可能做还出有用的成果。
透明干了一件事,把原本不需要显露出来的变动内容要显示出来。加重了显示处理的负担,就像表演的舞台,把后台成堆的道具、杂乱的人员调度、候场全部呈现出来,这末必会有一个好的结果。看来人要做小透明,末必是好事,也是一件代价极大的事。保护人的隐私从某种程度上也是节约社会的运行成本,社会需要的是最终积极的成果,个把八卦事情无关大局末必会被追查。也从侧面说明,保护社会运作的法律,是最低保障线,是低保线,不能做为个人的最高保护伞。
估计目前的技术水平下,用WS_EX_LAYERED、 UpdateLayeredWindow 是唯一有效的办法。逃不开WINAPI的魔爪。吃人家的用人家的,还想不要人家,要自由。法律上,虽然寄生只要不违法害死人,都没问题。当初你干嘛去了。只能做为反抗封建统治的样板戏。就像卢梭这样渣,在那时就是先驱者。各有各的理,找谁说去。
而且window各个版本的窗口实现机制还不一样,我去。

51.带有WS_EX_LAYERED风格的窗口也就是我们说的分层窗口,主要是为了了实现异形窗口和窗口整体透明。
若果要实现异形窗口则必须要设置这个风格,然后使用UpdateLayeredWindow函数来绘制,这样才能将控件的透明色和窗口后面的图像进行融合,从而绘制出带有透明效果的窗口
而要实现窗口的整体透明,则需要首先设置WS_EX_LAYERED风格,然后调用SetLayeredWindowAttribute函数设置透明度
以上所说的要想搞和透明相关的东西则必须设置这个分层风格,注意:
1、一旦调用UpdateLayeredWindow函数,WM_PAINT消息将失效,如果界面需要更新,则需要自己调用UpdateLayeredWindow函数
2、子窗口无法应用WS_EX_LAYERED风格,如果应用这个风格,将无法实现透明效果。也就是说这个窗口必须是非WS_CHILD;

52.SetWindowLong是一个Windows API函数。该函数用来改变指定窗口的属性.函数也将指定的一个32位值设置在窗口的额外存储空间的指定偏移位置。

53.终于明白,为什么窗口自己就是透明的。原来win7下用CreateWindow(Ex)创建的窗口本身是没有背景的。要后期WM_PAINT上去。流行的说法是后期render上去。难道是在XP下的经验出来问题?那时创建就有一个灰背景来着。不是很确定,估计是用的MFC框架的缘故。
https://docs.microsoft.com/en-us/windows/win32/learnwin32/painting-the-window

case WM_PAINT:
				{
					PAINTSTRUCT ps;
					HDC hdc = BeginPaint(hWnd, &ps);
					// All painting occurs here, between BeginPaint and EndPaint.
					FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
					EndPaint(hWnd, &ps);
				}
				return 0;

54.窗口创建的时候没有背景,但show以后会自动把第一次显示后,窗口后面的内容当成背景填充。移动窗口背景不更新,也就是不能实现真透明。一移动就露馅了。只有最小化,再恢复时再重新截取一次背景内容。最明显的特征就是,当后面窗口的内容是动画时,假装透明的窗口截取的内容不能显示动画,只是截取那一刻的静态内容。
有文章把透明度当透明窗口,真是醉了,透明窗口上还要画东西的,全透明了啥都没了。
看来只有一试,把有透明度的图片当背景试试。
好不容易实现了加载PNG,然而不能实现背景的刷新。
至少向前进了一步。核心函数就那么简单grpx.DrawImage(pImage,rect);

case WM_PAINT:
    {
        hdc = BeginPaint(hWnd, &ps);

        /*Image image(L"a1.png");
        Graphics graphics(hdc);
        graphics.DrawImage(&image, 0, 0);*/

        //GdiplusStartupInput gdiplusStartupInput;
        //ULONG_PTR gdiplusToken;
        //GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

        Rect rect(20, 20, 326, 326);
        Graphics grpx(hdc);
        Image* pImage = new Image(TEXT("a1.png"));
        //Image* pImage = Gdiplus::Image::FromFile(TEXT("a1.png"));
        grpx.DrawImage(pImage,rect);

        delete pImage;
        
        // shut down - only once per process
        //GdiplusShutdown(gdiplusToken);


        EndPaint(hWnd, &ps);
        return 0;

在这里插入图片描述

55.百度是学习程序语言的大障碍。商业、重复。包括CSDN也开始内卷,到处收费。搜索一个GDI+加载PNG,这都把人带沟里去了。最后人家明明白白的一篇就整得清清楚楚。这百度也学超市了,让你走最长的路。百度优先推CSDN装高深的,贴主要代码的,就是不写怎么绘制,然后就是收费下载的坑等着你。https://www.cnblogs.com/weekbo/p/9262047.html
人家搜索引擎一次搜索里还明明白白地搜到用GDI的程序:
https://www.cnblogs.com/zjutzz/p/10850382.html
让你可以比较GDI+与GDI的区别。
问,百度这是怎么了?

另附参考结果:
win32用GDI+加载png图片作为背景图
https://yq.aliyun.com/articles/245703
关于c ++:如何使用Win32 / GDI加载PNG图像(如果可能,不加载GDI +)?
https://www.codenong.com/4567875/

56.I should mention that there are really two types of layered window. The distinction comes down to whether you need per-pixel opacity control or you just need to control the opacity of the window as a whole. This article is about the former, but if you really just need to control the opacity of a window, you can do so by simply calling the SetLayeredWindowAttributes function after creating the window to set the alpha value.

57.WS_EX_LAYERED, invisible window, and a fresh install of Windows
事出反常必有妖。
After spending almost a day in searching for the solution, I found that the target PC (the one that hosts the executable) had the Aero Peek theme disabled because it had never run the “Performance Information and Tools”!

To create a layered window, specify the WS_EX_LAYERED extended window style when calling the CreateWindowEx function, or call the SetWindowLong function to set WS_EX_LAYERED after the window has been created. After the CreateWindowEx call, the layered window will not become visible until the SetLayeredWindowAttributes or UpdateLayeredWindow function has been called for this window. Note that WS_EX_LAYERED cannot be used for child windows.

according MSDN, when WS_EX_LAYERED is set:
"the layered window will not become visible until the
"SetLayeredWindowAttributes or UpdateLayeredWindow
“function has been called for this window”
工程活,来不得马虎。MSDN这坑很深。
妥妥的哦,给我出来,就这么简单。

SetLayeredWindowAttributes(
  hwnd,
  0, // no color key
  180, // alpha value
  LWA_ALPHA);

在这里插入图片描述

58.UpdateLayeredWindowIndirect
is similar to UpdateLayeredWindow but uses an UPDATELAYEREDWINDOWINFO structure to contain much of the information that is provided to UpdateLayeredWindow through its parameters.

The UpdateLayeredWindowIndirect function maintains the window’s appearance on the screen. The windows underneath a layered window do not need to be repainted when they are uncovered due to a call to UpdateLayeredWindowIndirect, because the system will automatically repaint them. This permits seamless animation of the layered window.

UpdateLayeredWindowIndirect always updates the entire window. To update part of a window, use the traditional WM_PAINT and set the blend value using SetLayeredWindowAttributes.
(理想很美好,现实很骨感。还是要悠着点用。)
For best drawing performance by the layered window and any underlying windows, the layered window should be as small as possible. An application should also process the message and re-create its layered windows when the display’s color depth changes.

This first thing to notice is that there’s no need to call UpdateWindow since this code doesn’t use WM_PAINT. Instead it immediately calls the Render method, which in turn is required to perform some drawing and to provide a DC to LayeredWindowInfo’s Update method. How that drawing occurs and where the DC comes from is where it gets interesting.

59.《Windows with C++ - Layered Windows with Direct2D》
这篇文章的功力,降龙十八掌。
https://docs.microsoft.com/en-us/archive/msdn-magazine/2009/december/windows-with-c-layered-windows-with-direct2d

60.如同Windows“窗口类”一样,设备描述表也是一种Windows数据结构,用来描述绘制窗口所需要的信息。它定义了一个坐标映射模式、一组GDI图形对象及其属性。这些GDI对象包括用于画线的笔,绘图、填图的刷子,位图,调色板,剪裁区域,及路径(Path)。

Common设备描述表通过::GetDC,::GetDCEx,::BeginPaint来获得一个设备描述表,用毕,用::ReleaseDC或::EndPaint释放设备描述表;
Printer设备描述表通过::CreateDC创建设备描述表,用::DeleteDC删除设备描述表。Memory设备描述表通过::CreateCompatibleDC创建设备描述表,用::DeleteDC删除。
Information设备描述表通过::CreateIC创建设备描述表,用::DeleteDC删除。

在如MS-DOS的单任务系统里面,正在运行的应用程序可以自由的做它想做的事情,无论是在屏幕上画线还是重新编写调色板。但是在windows下的多任务环境下,程序却没有如此的自由,A程序的输出是不可以影响B程序的输出的,所以每个程序都被严格的限制于它本身的窗口。GDI用简单的机制确保每个程序的绘制在上面的规则下执行,这个机制就是Device Context(DC)。当一个windows程序向屏幕,打印机等输出设备绘制时,它不是直接在设备绘制的,而是绘制在一个由DC(Device Context)表示的“Display Surface”上面的。

一个DC是在windows底层下的结构体,包含了GDI需要知道“display surface”的所有东西,包括和它相关的物理设备。当要在屏幕绘制时,应用程序需要从GDI获得一个DC句柄,然后当要调用GDI的输出函数时,就把这个句柄传递给它。通过DC,GDI可以保证程序的所有绘制都限制在屏幕的指定区域。

利用GDI进行图形、图像处理的一般操作步骤为:1. 取得指定窗口的DC。2. 确定使用的坐标系及映射方式。3. 进行图形、图像或文字处理。4. 释放所使用的DC。但是,在GDI+中,只需将Pen对象直接作为参数传递给Graphics类的DrawLine等方法即可,而不必使Pen对象与 Graphics对象关联。

61.UpdateLayeredWindow方式实现异型窗口

  1. 窗口属性必须是Top Window,子窗口(Win8之前的操作系统)不支持实现异形窗口

  2. Layer Window没有WM_PAINT消息,需要自己调用OnPaint

  3. 窗口属性可设置为

WS_POPUP | WS_VISIBLE, WS_EX_TOOLWINDOW | WS_EX_LAYERED

62.掉钱眼里的谋平台与掉钱眼里的某度。这界面像极了股票投资账户。为什么在这里?因为某度搜索总能找到这里。人们是不是被PUA了。在这里插入图片描述
63.有人忙榨取每一个钢崩儿,而有人忙着开源。感谢真神存在的地方。实现了透明,还有透明区还鼠标穿透。而且可贵的是,作死不显示窗口的UpdateLayeredWindow,在那里有了编译成功的实例。那些把代码掐头去尾,一心赚钱的砖家给的提示没一个有用的。现在网络的环境对于自学的初学者是十分不友好的,某度导流到骗钱的坑里,而不是真正知识里。
在这里插入图片描述
64. 网上一直强调WS_EX_LAYERED不能有子窗口,但不是说它不能成为别人的子窗口。不能当爹,可以当人家的儿子、孙子。WS_EX_LAYERED这样的定位有点尴尬,好在window8下面说是能翻身做主人。

	hwnd = CreateWindowEx (
	WS_EX_LAYERED|WS_EX_TOPMOST|WS_EX_APPWINDOW,                   /* Extended possibilites for variation */
	szClassName,         /* Classname */
	"PNG transparent",       /* Title Text */
	WS_OVERLAPPEDWINDOW, /* default window */
	CW_USEDEFAULT,       /* Windows decides the position */
	CW_USEDEFAULT,       /* where the window ends up on the screen */
	500,                 /* The programs width */
	500,                 /* and height in pixels */
	HWND_DESKTOP,        /* The window is a child-window to desktop */
	NULL,                /* No menu */
	hThisInstance,       /* Program Instance handler */
	NULL                 /* No Window Creation data */
	);

65.都会给人看病了。
给窗口添加拖动功能。发现一网友的求助帖。在用python,给QT窗口加拖动时碰到过。不知道对不对,助人为乐先吧。
在这里插入图片描述
在这里插入图片描述

MFC的坑呀,就像人类早期的化妆水平(那鬼样)。没有KFC那样快捷。还是用WINAPI称心。

case WM_LBUTTONDOWN:
		printf("LButtonDown");
		GetCursorPos(&ptCur);//拖动起始位置
		//::PostMessage(hwnd,WM_NCLBUTTONDOWN,HTCAPTION,lParam);
		break;
	case WM_PAINT:
	
		break;
	case WM_MOUSEMOVE:	
		
		if(wParam==MK_LBUTTON)
		{
			POINT ptNow;
			RECT wndRect;
			::GetWindowRect(hwnd,&wndRect);			
			GetCursorPos(&ptNow);			
			int x=ptNow.x-ptCur.x;
			int y=ptNow.y-ptCur.y;
			GetCursorPos(&ptCur);//没有这一句窗口会跳。现在位置是下次移动事件的开始位置,婆媳转换。
			MoveWindow(hwnd,wndRect.left+x,wndRect.top+y,380,380,true);					
		}
		break;

66.透明的目标一下子实现了,忽然不知道下一步做啥了。捋一下。
a.找一下以前为什么不有成功的原因。
b.朝着自己绘图的道路前进
c.游戏编程
d.其他几种实现透明窗口的办法。

67.一步回到最初准备用DX实现的道路。

68.注释:内存设备上下文环境是仅在内存中存在的设备上下文环境,当内存设备上下文环境被创建时,它的显示界面是标准的一个单色像素宽和一个单色像素高,在一个应用程序可以使用内存设备上下文环境进行绘图操作之前,它必须选择一个高和宽都正确的位图到设备上下文环境中,这可以通过使用CreateCompatibleBitmap函数指定高、宽和色彩组合以满足函数调用的需要。

A memory device context is a block of memory that represents a display surface. It can be used to prepare images in memory before copying them to the actual device surface of the compatible device.
When a memory device context is created, GDI automatically selects a 1-by-1 monochrome stock bitmap for it. GDI output functions can be used with a memory device context only if a bitmap has been created and selected into that context.

69.CreateCompatibleDC前者像准备的一个画布,WS_EX_LAYERED一定要显示点东西否则不显示?
问题找到了,UpdateLayeredWindow最后一参数造成了,全透明。不是不显示,而是真正全透明。这不,底层位图、画的文字都出来了。最后一参数,由2改成1。就这么简单,就这么神奇。
BOOL bRet=UpdateLayeredWindow(hwnd,screenDC,&ptSrc,&wndSize,hdcSrc,&ptSrc,0,&blendFunction,1);
在这里插入图片描述
70.正被StretchBlt折磨。不能实现缩放。

BOOL bStr=StretchBlt(hDC, 0, 0, rc.right,rc.bottom, hdcSrc, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);

试验了几十次无果。先放放,都快抓狂了。
窗口程序无法用控制台输出信息。get到一个法子,不错的。没有搜到string到宽字符的方法。最后暴力MessageBoxA输出,爽。
stringstream ss; ss<<rc.right<<’\t’<<rc.bottom<<’\t’<<bmp.bmWidth<<’\t’<<bmp.bmHeight;
string s1 = ss.str();
MessageBoxA(nullptr,s1.c_str(),"",0);

无论怎么修改参数都不起作用。怀疑StretchBlt的结果没有作用。显示的图像,也只是UpdateLayeredWindow的功劳。
思路有了。StretchBlt要画WS_EX_LAYERED的hDC,人家压根不理你。WS_EX_LAYERED显示只有两条路,一个是SetLayeredWindowAttributes、一个是UpdateLayeredWindow。网上的例子都是直接输出到窗口句柄了,而在WS_EX_LAYERED中要起作用,只有想法子在兼容DC(hdcSrc)上想办法,然后交给UpdateLayeredWindow输出才会用效。没办法,WS_EX_LAYERED是新来的姑娘,场子有大哥承包着,其他小弟只能硬闯。学学人家,成功的例子是DrawText兄弟。

DrawText(hdcSrc,L"Center Line Text",-1,&rc,DT_LEFT|DT_SINGLELINE|DT_TOP);//在兼容DC中间位置输出字符串

管他行不行,直接把目标DC写成兼容DC。搞一下试试。就这么霸气。
结果:成了。
这次花算是送上了。但是碜人,碜得慌,这哪能用来送人?
后面用上了网络上兄弟的妙方SetStretchBltMode(hdcSrc,COLORONCOLOR); 。下面是两次运行的对比。

SetStretchBltMode(hdcSrc,COLORONCOLOR);						
BOOL bStr=StretchBlt(hdcSrc, 0, 0, 380,380, hdcSrc, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);

在这里插入图片描述
在这里插入图片描述
71.明白了一个道理,我们不是迷恋池子里的姑娘,而是迷恋上场子后面的大哥。我们不能直接迷恋大哥,人家大哥也没这癖好,但可以喜欢上池子里姑娘,她们是场子里大哥的姑娘。真心喜欢她们就是真心喜欢大哥。以后出门就说去会大哥。

72.下一步就是实现指定颜色透明。UpdateLayeredWindow修改两个参数实现。
至此应该算是打通UpdateLayeredWindow透明的任督二脉。
在这里插入图片描述

BOOL bRet=UpdateLayeredWindow(hwnd,screenDC,&ptSrc,&wndSize,hdcSrc,&ptSrc,RGB(255,255,255),&blendFunction,1);

73.Cimage image都是MFC、ATL。Cximage是第三方库。
在没有接触Gdiplus之前,在vc中绘制图片,通常加载一张位图,然后进行贴图。对于现在多种多样的图片格式,之前的GDI并不支持(应该是这样的,呵呵)。而使用Gdiplus则可以选择多种图片格式,比如BMP, ICON, GIF, JPEG, Exif, PNG, TIFF, WMF, and EMF。

74./问题出在这里。循环DrawImage造成窗口卡死。
int j=0;
while(j<10000){
//问题出在这里。循环Draw造成窗口卡死。
graphics.DrawImage(pSrc, m_pt.x, m_pt.y, hmWidth, hmHeight);

	j++;
	}

视频显示中对图片的处理效率要求比较高,当图像的尺寸比较小时,drawimage的绘图效率没问题,但当分辨率高时,视频莫名奇妙的总是卡住。

关于GDI和GDI+
GDI的效率更高,而GDI+无疑更加易用,鱼与熊掌不可兼得。
我现在的做法是用GDI+画到内存Bitmap上,最后用GDI BitBlt画到DC上。

BOOL CreateDib(int w, int h, OUT HBITMAP& hBmpSection, OUT BYTE** bmpData) ; 

BYTE* bmpData;
//下面这句报内存溢出,问题是定义变量出问题。**定义时是*,传送时用&
CreateDib(wndSize.cx,wndSize.cy,hBmpSection,&bmpData);
			

The Bitmap::LockBits method locks a rectangular portion of this bitmap and provides a temporary buffer that you can use to read or write pixel data in a specified format. Any pixel data that you write to the buffer is copied to the Bitmap object when you call Bitmap::UnlockBits.

//下面这句报内存溢出
pMemBitmap->LockBits(&rct, ImageLockModeRead | ImageLockModeUserInputBuf, pMemBitmap->GetPixelFormat(), &data);

75每一处单独看起来很好的样子,但是放一起不美好开始了。

1,是什么导致背景的layered window在调用了UpdateLayeredWindow之后又开始收到WM_PAINT消息?WIN+D按下之后发生了什么?

第一个问题,我请教了Windows组的SDE,他说是一个“Old USR bug”,丢给DefWindowProc即可,不需要在此重绘layered window。

76.为什么微软这里实现不把透明度带上呢,结合GDI Bitblt等函数也都不支持Alpha操作,我猜可能是GDI+设计时候HBITMAP支持Alpha还比较弱,所以干脆不读取了,可能还是有别的考虑,知道内幕的请留言,学习下。

之所以将GDI+ Bitmap和GDI HBITMAP互转单独挑出来写下,是因为实际应用中经常我们需要GDI和GDI+换用,特别是需要兼顾效率和渲染效果的场合,更是通常使用GDI+做平滑/抗锯齿,用GDI做常规绘图。
熟悉GDI+的人已经知道,GDI+本身已经提供了HBITMAP和Bitmap转换的函数:
HBITMAP->Bitmap 构造函数或FromHBITMAP
Bitmap->HBITMAP GetHBITMAP
对于无透明度的图像来说,直接调用没有问题,但是对应带透明度的图像,使用时就有问题了,所以本文重点讨论的是带透明度的HBITMAP和Bitmap的转换。

77.程序代码的控制区与数据区。交易市场与仓库。库存管理系统、所有权交易系统。

78.因为函数参数是按值传递的,所以要想改变变量,必须传递地址。
二级指针实际上就是指针变量的地址,如果传递二级指针,函数声明必须写**。
(void**)&必须是本质上就是指针变量的地址才可以做这样的转换,并不是说把一个一级指针也可以转换,void**的本质是标识一个二级指针。
&data就是(默认数据类型 **)&data,(void **)&data和&data还是同一块内存,只不过数据类型发生变化了。
如果默认数据类型是int,&data就是(int **)&data

79.The BitmapData class is used by the Bitmap::LockBits and Bitmap::UnlockBits methods of the Bitmap class. A BitmapData object stores attributes of a bitmap.

Type: BitmapData*

Pointer to a BitmapData object. If the ImageLockModeUserInputBuf flag of the flags parameter is cleared, then lockedBitmapData serves only as an output parameter. In that case, the Scan0 data member of the BitmapData object receives a pointer to a temporary buffer, which is filled with the values of the requested pixels. The other data members of the BitmapData object receive attributes (width, height, format, and stride) of the pixel data in the temporary buffer. If the pixel data is stored bottom-up, the Stride data member is negative. If the pixel data is stored top-down, the Stride data member is positive. If the ImageLockModeUserInputBuf flag of the flags parameter is set, then lockedBitmapData serves as an input parameter (and possibly as an output parameter). In that case, the caller must allocate a buffer for the pixel data that will be read or written. The caller also must create a BitmapData object, set the Scan0 data member of that BitmapData object to the address of the buffer, and set the other data members of the BitmapData object to specify the attributes (width, height, format, and stride) of the buffer.

Bitmap::LockBits and Bitmap::UnlockBits must be used as a pair. A call to the Bitmap::LockBits method of a Bitmap object establishes a temporary buffer that you can use to read or write pixel data in a specified format. After you write to the temporary buffer, a call to Bitmap::UnlockBits copies the pixel data in the buffer to the Bitmap object. If the pixel format of the temporary buffer is different from the pixel format of the Bitmap object, the pixel data is converted appropriately.

79.IN OUT

(3)现实编程中,一个函数需要返回多个值是非常普遍的,通常的做法是用参数来返回。

在典型的Linux返回值是不用来返回结果的,返回值的作用是用来返回0或者一个负数,用来表示程序执行的结果是对还是错的。

(4)普遍的做法,编程中函数的输入和输出都是靠函数的参数的,返回值只是用来表示函数的执行结果是对的还是错。

(5)如果这个函数是用来做输入的,也叫做输入型参数,用来做输出的就叫做输出型参数。输出型参数就是让函数把函数内部把数据输出到函数的外部的。

80.Copy individual frames from a multiple-frame image

The code constructs an Image object from the multiple-frame TIFF file. To retrieve the individual frames (pages), the code calls the Image::SelectActiveFrame method of that Image object. The first argument passed to the Image::SelectActiveFrame method is the address of a GUID that specifies the dimension in which the frames were previously added to the multiple-frame TIFF file. The GUID FrameDimensionPage is defined in Gdiplusimaging.h. Other GUIDs defined in that header file are FrameDimensionTime and FrameDimensionResolution. The second argument passed to the Image::SelectActiveFrame method is the zero-based index of the desired page.

The code relies on the helper function GetEncoderClsid, which is shown in Retrieving the Class Identifier for an Encoder.

GUID   pageGuid = FrameDimensionPage;
CLSID  encoderClsid;
Image  multi(L"Multiframe.tif");

// Get the CLSID of the PNG encoder.
GetEncoderClsid(L"image/png", &encoderClsid);

// Display and save the first page (index 0).
multi.SelectActiveFrame(&pageGuid, 0);
graphics.DrawImage(&multi, 10, 10);
multi.Save(L"Page0.png", &encoderClsid, NULL);

// Display and save the second page.
multi.SelectActiveFrame(&pageGuid, 1);
graphics.DrawImage(&multi, 200, 10);
multi.Save(L"Page1.png", &encoderClsid, NULL);

// Display and save the third page.
multi.SelectActiveFrame(&pageGuid, 2);
graphics.DrawImage(&multi, 10, 150);
multi.Save(L"Page2.png", &encoderClsid, NULL);

// Display and save the fourth page.
multi.SelectActiveFrame(&pageGuid, 3);
graphics.DrawImage(&multi, 200, 150);
multi.Save(L"Page3.png", &encoderClsid, NULL);

80.还是老老实实写gif的读取类吧。

81.读取gif之路上的神操作,终于出现了。
gif结构与read顺序读取之间的天作之合,一个字,绝!
read(gif->fd, &sep, 1);
In order to properly use extension hooks, it’s necessary to understand
how GIF files store variable-sized data. A GIF block of variable size is
a sequence of sub-blocks. The first byte in a sub-block indicates the
number of data bytes to follow. The end of the block is indicated by an
empty sub-block: one byte of value 0x00. For instance, a data block of
600 bytes is stored as 4 sub-blocks:

255, <255 data bytes>, 255, <255 data bytes>, 90, <90 data bytes>, 0

gd_get_frame(gd_GIF *gif)
{
    char sep;
    dispose(gif);
    read(gif->fd, &sep, 1);
    while (sep != ',') {
        if (sep == ';')
            return 0;
        if (sep == '!')
            read_ext(gif);
        else return -1;
        read(gif->fd, &sep, 1);
    }
    if (read_image(gif) == -1)
        return -1;
    return 1;
}

82.编译一个开源项目时提示error C4576: a parenthesized type followed by an initializer list is a non-standard explicit type conversion syntax,在网上搜了下,是E文,原文如下:
Check your compilation settings to see if it by any chance includes a /TP (“compile as C++”) switch.
我不懂E文,不知在什么地方设置,请高手或路过的朋友支个招。

83.没有控制台的日子里,怎么过?又是一个神操作。
我们可以在应用程序里自己开一个控制台(就像DOS窗口一样),然后重定向输入输出,就可以用printf函数向控制台输出信息了,具体方法如下。
AllocConsole();
freopen(“CONOUT " , " w + t " , s t d o u t ) ; f r e o p e n ( " C O N I N ","w+t",stdout); freopen("CONIN ","w+t",stdout);freopen("CONIN”,“r+t”,stdin);

执行以上三个函数后,如果没有错误就会出现一个控制台,并且重定向了输入输出,然后就可以使用printf了。

最后,不要忘记FreeConsole();关闭控制台。

83.离目标似乎又近了。一位朋友实现,将一个正弦曲线写入24位的BMP。感觉一步到位了数据可视化的小目标。实现的功能简单,但这已经可以看到登天的路径。
https://blog.csdn.net/kupepoem/article/details/43307387

在这里插入图片描述

84.继续在gif的路上行进。第一次取到能见看图像影子的图。虽然是倒的,而且扭曲、颜色不对、估计数据还错位。
为毛用图的宽度不行,一定要加1?
void saveBitmap(int nwidth,int nheight,BYTE bits)
{
// Define BMP Size
// Define BMP Size
const int height = nheight;
const int width = nwidth+1;//要+1才行。


在这里插入图片描述
85.传值,传参。被WIN32迷之表达式都带沟里去了。
(void
*)&m_pBits,这样的见了就头晕。
常说的int a=3;其实已经是加了一层包装,只是代表的传值。真实的a是不存在的,a只存在于cpp文件中。真实的a就是一个地址。如果定义指针int *a=3,会多开一个单元存储值3所在地址a。a=3是直接寻址, *a=3是间接寻址。一层指针就是多了一个兄弟帮衬,多了一个弟兄把门。再多一层就是自己的弟兄又找了一个哥们儿。我和兄弟是亲的,和兄弟的哥们儿就不一定认亲戚了。
也可以想是多一层指针就是找一老婆来管理一下,再一层就有点狗血剧了,这样的关系容易出问题。

通过bitmapHeader.biHeight = -height,实现图像变正。这看起来舒服一点。
图象的高度,以象素为单位。这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,即:数据的第一行其实是图像的最后一行,如果该值是一个负数,则说明图像是正向的。

// Part.2 Create Bitmap Info Header
	BITMAPINFOHEADER bitmapHeader = { 0 }; 
	bitmapHeader.biSize = sizeof(BITMAPINFOHEADER);
	bitmapHeader.biHeight = -height;
	bitmapHeader.biWidth = width;
	bitmapHeader.biPlanes = 1;//1、3都可以
	bitmapHeader.biBitCount = 24;//32出不图,biBitCount是图像的位数,例如24位,8位等

在这里插入图片描述
86.C与C++之间的小秘密。
error C2036: 'void ': unknown size
在32位机中,地址是一个4字节长的正整数,而指针是用来存放地址的,当我们定义一个指针,如char
p;的时候,系统为p分配了一个4字节的内存空间,里面存放的值,实际上是一个unsigned long类型(但是如果未转换为unsigned long ,在VC++中则还是会出错),用来标识地址;这个地址标识着一个char单元的首地址,当然char只占有1一个字节。直接强制转化为ULONG也是对的,因为这是个未知类型的32位正整数,所以强制转换也可以用ULONG;当然用其他的类型不会报错,但会导致数据截断等错误。

87.费心费力编译通过的example,速度慢不说,图片还出白杂点。
目的是验证gif读取函数有没有问题。从图像上看,应该没有大问题,读取效率上存疑。
在这里插入图片描述

88.色深24位的位图
★ 每一行的字节数必须是4的整数倍,如果不是,则需要补齐;(bitSizeImage中提到过)
★ BMP文件的数据存放是从下到上,从左到右的。也就是说,从文件中最先读到的是图像最下面的左边第一个像素,然后是左边第二个像素,接下来是倒数第二行左边第一个像素,左边第二个像素,依次类推
每个像素用3个字节表示,顺序依次为红,绿和蓝的值。每行用0填充到4字节的边界。
已知图片尺寸,做一个简易的对齐操作。爽歪歪的内存操作。结果也如预期。

//要+1才行。因为要是4的倍数 647*361
uint8_t *buffer4,*dest;
buffer4= (uint8_t )malloc((gif->width+1) * gif->height * 3);
memset(buffer4,0,(gif->width+1) * gif->height * 3);
dest=buffer4;
src=buffer;
for (int i = 0; i < gif->height; i++) {
dest=buffer4+(gif->width+1)i3;
src=buffer+(gif->width)i3;
memcpy(dest,src,gif->width
3);
}
saveBitmap(gif->width+1,gif->height,buffer4);
在这里插入图片描述

颜色怎么了?
果然如我所猜想的,RGB的顺序,估计原数据是BGR。结果喜人。正面目来了。
这种格式的转换的确是无谓增加系统的负担。又或者解码函数里有点小问题,没有针对BMP的优化。到底哪一种是系统最终使用时的顺序呢?

uint8_t *buffer,*src;
gd_GIF * gif=main_2(&buffer);

uint8_t *buffer2,*dest2,*color;
buffer2= (uint8_t *)malloc((gif->width) * gif->height * 3);
memset(buffer2,0,(gif->width) * gif->height * 3);
dest2=buffer2;
src=buffer;
color=buffer;	
for (int k=0;k<gif->width * gif->height * 3;k+=3){		
	dest2[0]=color[2];
	dest2[1]=color[1];
	dest2[2]=color[0];
	color=buffer+k;
	dest2=buffer2+k;
}	
buffer=buffer2;

在这里插入图片描述

89.CreateDIBSection、CreateDIBitmap 傻傻分不清楚。
The CreateDIBSection function creates a DIB that applications can write to directly. The function gives you a pointer to the location of the bitmap bit values. You can supply a handle to a file-mapping object that the function will use to create the bitmap, or you can let the system allocate the memory for the bitmap.

The CreateDIBitmap function creates a compatible bitmap (DDB) from a DIB and, optionally, sets the bitmap bits.
首先明确最主要区别:CreateDIBitmap创建的是设备相关位图句柄 - HBITMAP.
CreateDIBSection创建的是设备无关位图句柄 - HBITMAP.
DIB和DDB之间的相互转换比较慢(关于DIB与DDB区别详见《设备相关(DDB)与设备无关(DIB)》),所以我们使用CreateDIBSection()来创建一个DIB区块。这样作图速度快。
CreateDIBSection()返回的是一个HBITMAP,CreateDIBitmap()返回的也是HBIT MAP。
两者的区别在于:CreateDIBSection创建的是一个DIBSECTION结构,
CreateDIBitmap创建的是BITMAP结构。

1、关于CreateDIBSection函数的使用需要注意一点就是参数ppvBits的使用:传给CreateDIBSection函数的不是一个new
出来一块的空间,也不是直接传入真实像素指针pImageData,而只是传入一个指针变量(如本例中的pArray)用以接收CreateDIBSection自动开辟的像素区域指针!如果你传入了自己手动new出来的一块区域,在Debug调试运行时会发现一个delete []错误,此错误指明你之前new出来的空间无法释放,原因是堆损坏,这部分需要了解下new、delete(或内存检测)原理,详见《new/delete内存分配及释放检测》。
2、像素数据的复制必须在调用了CreateDIBSection函数之后进行,如本例所示,memcpy(pArray, pImageData, uiTotalBytes);是在HBITMAP hbmp = CreateDIBSection(NULL, &bmpInfo, DIB_RGB_COLORS, &pArray, NULL, 0);之后进行的。可能是由于CreateDIBSection函数会对传入的像素空间进行“清除”工作,所以在调用此函数前就先进行像素复制的话,你会发现最终绘制的图像时一片漆黑!

那么多次的失败,终于找到原因了。
在这里插入图片描述

终于见到了天日!不完美,但很成功!

 m_hBmp = CreateDIBSection(m_hDC, (BITMAPINFO*)&bih,DIB_RGB_COLORS, (void**)(&buffer3), NULL, 0);
 //m_hBmp = CreateDIBitmap (m_hDC, &bih+1,DIB_RGB_COLORS, (void**)(&buffer4), (BITMAPINFO*)(&bih+1), 0);
 SelectObject(m_hDC, m_hBmp);//把内容挂到DC上。.
 memcpy(buffer3, buffer4, (gif->width+1)*gif->height);

在这里插入图片描述
转转更健康。人家也是转的,但他帮助到了。
https://www.cnblogs.com/staring-hxs/p/3264896.html

修成正果。

 m_hBmp = CreateDIBSection(m_hDC, (BITMAPINFO*)&bih,DIB_RGB_COLORS, (void**)(&buffer3), NULL, 0);
 SelectObject(m_hDC, m_hBmp);//把内容挂到DC上。.
 memcpy(buffer3, buffer4, (gif->width+1)*gif->height*3);
RECT wndRect;
GetWindowRect(hwnd,&wndRect);
SIZE wndSize = {wndRect.right-wndRect.left,wndRect.bottom-wndRect.top};
SetStretchBltMode(hDC,COLORONCOLOR);	
BOOL bStr=StretchBlt(hDC, 0, 0, wndSize.cx,wndSize.cy, m_hDC, 0, 0, gif->width+1,gif->height, SRCCOPY);

在这里插入图片描述

89.出同样的问题连续画gif后两秒左右窗口卡死。感觉应该把播放功能放在WM_PAINT事件中。

在这里插入图片描述
90.窗口本身可能应该包装了太多的东西。其中肯定有许多美丽的谎言、许多障眼法。敢不敢自己画窗口。有都有rgb数据了,还怕什么。

91.没有使用默认参数前,不知道申明的重要性。
void saveBitmap(int width,int height,BYTE bits,char name=“output.bmp”);

char *name=“output0”;
printf(“name:%d,%s\n”,(int)name,(char *)(name+1));
printf(“name:%d,%s\n”,(int)name,(name+1));

该来的总会来。
因为事实的真相却是你向change函数传递了一个无法被更改的字符串

确保你想要修改的char*是可以修改的 https://www.cnblogs.com/magicsoar/p/3721658.html
好吧,让我们看下下面的代码
char *a = “Peter”;
char b[] = “Peter”;
char *c = new char[6];
strcpy_s(c, 6, “Peter”);
a,b,c三个指针所指的内容都是peter,但这三个peter却位于不同的地方
a所指的Peter位于常量区
b所指的位于栈上
c所指的位于堆上

但你可以让a指向一个新的地方,因为a是一个指针
但对于位于栈上的b来说,你可以修改b所指的内容,
不要将一个字符串直接传递给一个函数或者赋值给一个char类型的指针,除非你知道这个字符串中的字符的内容不会被改变
如何你可能会修改这个字符串的值,请使用char[],如果想使用字符串不变量,请使用const char

92.不论是否有图片画上,窗口在循环时自动卡死。大神单独开线程播放还是有一手的。

93.我也来一个神仙操作,用老神仙级别的代码。保持位数对齐。

在这里插入图片描述

int x=100;
while (gd_get_frame(gif)) {		
gd_render_frame(gif, buffer);
changetobmpdata(width,height);
char name[128]="output";
printf("name:%d,%s\n",(int)name,(name+1));
char index[32];
itoa(x,index,10);
//index+1把前面的数字去掉,保证位数对齐。更快的左移操作都解决不了问题
strcat(name,index+1);
strcat(name,".bmp");
printf("name:%s\n",name);
x++;
saveBitmap(width+1,height,buffer4,name);	
}

94 Win32进程间通信的方式主要有:
  (1)剪贴板(Clip Board);
  (2)动态数据交换(Dynamic Data Exchange);
  (3)部件对象模型(Component Object Model);
  (4)文件映射(File Mapping);
  (5)邮件槽(Mail Slots);
  (6)管道(Pipes);
  (7)Win32套接字(Socket);
  (8)远程过程调用(Remote Procedure Call);
  (9)WM_COPYDATA消息(WM_COPYDATA Message)。
  
如果不使用VC多线程C运行时库来生成多线程程序,必须执行下列操作:
  (1)使用标准 C 库(基于单线程)并且只允许可重入函数集进行库调用;
  (2)使用 Win32 API 线程管理函数,如 CreateThread;
  (3)通过使用 Win32 服务(如信号量和 EnterCriticalSection 及 LeaveCriticalSection 函数),为不可重入的函数提供自己的同步。

如果使用标准 C 库而调用VC运行时库函数,则在程序的link阶段会提示如下错误:
error LNK2001: unresolved external symbol __endthreadex
error LNK2001: unresolved external symbol __beginthreadex

	需要调用到CRT库时,不要用CreateThread 创建线程、并用CloseHandle来关闭这个线程,而应该用_beginthread来创建线程,_endthread来销毁线程。因为没有对子线程为CRT库分配堆,会导致低内存错误而崩溃。
	crt 运行时库是程序在运行时所需要的库文件,通常运行时库是以LIB或DLL形式提供的。C运行时库诞生于20世纪70年代,当时的程序世界还很单纯,应用程序都是单线程的,多任务或多线程机制在此时还属于新观念。
	我们知道在Windows下创建一个线程的方法有两种,一种就是调用Windows API CreateThread()来创建线程;另外一种就是调用MSVC CRT的函数_beginthread()或_beginthreadex()来创建线程。相应的退出线程也有两个函数Windows API的ExitThread()和CRT的_endthread()。这两套函数都是用来创建和退出线程的,它们有什么区别呢?

95.使用_beginthread()后界面不卡死。
在这里插入图片描述
96.搞死个仙人伯伯了。
在全局变量区初始化了窗口句柄,那时窗口都还没有建。后面没有再次赋值,结果窗口就是不显图。
HWND hDC=GetDC(hWnd);
后面保险起见,还是重新赋值一次。
hDC=GetDC(hWnd);

修正这个Bug后奇迹终于出现。
向死而生,凤凰涅槃。
MARK一下。2021/2/19 20:15,一个历史性的时刻。
去你的花里胡哨、装逼的多线程代码。这里一句实现
_beginthread( readgif, 0, NULL );

修改后终于看到了不卡死的窗口。算是实现了自己的播放器。与WM_PAINT无关,反而在LRESULT CALLBACK WindowProcedure回调函数中加了这个事件,CPU马上占50%。
在这里插入图片描述

奇迹在继续!
GDI+绘图的程序做了多线程改造,顺利实现无卡窗口播放。
有一种强烈的冲动,最终的实现就在左右。

HDC hdc = ::GetDC(hWnd);
HDC screenDC = GetDC(NULL);
HDC memDC = ::CreateCompatibleDC(hdc);
//下面两句不能少
HBITMAP memBitmap = ::CreateCompatibleBitmap(hdc,wndSize.cx,wndSize.cy);
::SelectObject(memDC,memBitmap);

奇迹在继续!
GDI+绘图的程序多线程改造,顺利实现多层窗口播放!!完美置顶、无边框。
在这里插入图片描述

97.修正一个bug。原来目标屏幕的起始位置为{0,0}。应该根据窗口的移动而变动起始位置。

while(TRUE)
{

gc.DrawImage(&img,0,0,img.GetWidth(),img.GetHeight());

img.SelectActiveFrame(&guid,fcount++);
if (fcount == nFrameCount)
{
	fcount = 0;
}
POINT ptStart = {100,100};
//需要更新&ptSrc,否则会在移动窗口的时候起冲突。
RECT wndRect;
::GetWindowRect(hWnd,&wndRect);
ptStart.x=wndRect.left;
ptStart.y=wndRect.top;
long pause = ((long*)pItem->value)[fcount]*10;
BOOL bRet2=UpdateLayeredWindow(hWnd,screenDC,&ptStart,&wndSize,memDC,&ptSrc,0,&blendFunction,2);	
Sleep(pause);

}

98.鼠标穿透。
关键就是设置WS_EX_TRANSPARENT

LONG lStyle;
lStyle = GetWindowLong(hDlg, GWL_EXSTYLE);
setWindowLong(hDlg, GWL_EXSTYLE, lStyle | WS_EX_TRANSPARENT | WS_EX_LAYERED);

		/* The class is registered, let's create the program*/
		//WS_EX_TRANSPARENT 实现鼠标穿透
		  hWnd= CreateWindowEx (
			WS_EX_LAYERED|WS_EX_TOPMOST|WS_EX_APPWINDOW|WS_EX_TRANSPARENT ,                   /* Extended possibilites for variation */
			szClassName,         /* Classname */
			L"PNG transparent",       /* Title Text */
			WS_OVERLAPPEDWINDOW, /* default window */
			CW_USEDEFAULT,       /* Windows decides the position */
			CW_USEDEFAULT,       /* where the window ends up on the screen */
			380,                 /* The programs width */
			380,                 /* and height in pixels */
			HWND_DESKTOP,        /* The window is a child-window to desktop */
			NULL,                /* No menu */
			hThisInstance,       /* Program Instance handler */
			NULL                 /* No Window Creation data */
			);

99.MoveWindow,改变窗口的大小;UpdateLayeredWindow 更新一个分层窗口的位置,大小 。
hWnd指定了窗口的句柄
x指定了CWnd的左边的新位置。
y指定了CWnd的顶部的新位置。
nWidth指定了CWnd的新宽度。
nHeight指定了CWnd的新高度。
函数功能:改变指定窗口的位置和大小.对基窗口来说,位置和大小取决于屏幕的左上角;对子窗口来说,位置和大小取决于父窗口客户区的左上角.对于Owned窗口,位置和大小取决于屏幕左上角.
函数原型:BOOL MoveWindow( HWND hWnd, int X, int Y, int nWidth, int nHeight, BOOL bRepaint );

UpdateLayeredWindow
UpdateLayeredWindow函数更新一个分层窗口的位置,大小,形状,内容和半透明度。
BOOL WINAPI UpdateLayeredWindow(
In HWND hwnd,
In_opt HDC hdcDst,
In_opt POINT *pptDst,
In_opt SIZE *psize,
In_opt HDC hdcSrc,
In_opt POINT *pptSrc,
In COLORREF crKey,
In_opt BLENDFUNCTION *pblend,
In DWORD dwFlags
);

100.透明度背景图片出现残留。在这里插入图片描述

通过内存置0,解决。强大的CreateDIBSection,CreateCompatibleBitmap没法比。

while(TRUE)
{
	memset(bmpData,0,desk.right*desk.bottom*32/8);
	Sleep(50);	
	gc.DrawImage(img,0,0,nowSize.cx,nowSize.cy);	 
	img->SelectActiveFrame(&guid,fcount++);
	if (fcount == nFrameCount)
	{
		fcount = 0;
	}
	long pause = ((long*)pItem->value)[fcount]*10;
	UpdateLayeredWindow(hWnd,screenDC,&ptStart,&nowSize,memDC,&ptSrc,0,&blendFunction,2);
	Sleep(pause);
}

101 DirectX播放视频。DX也是一个包装。
很多人第一次接触到DirectX大都是通过游戏,至于安装、升级DirectX的原因无非是满足游戏运行的需要。Direct X其实是微软公司推出的一个为Windows平台的多媒体API函数库,它提供标准接口来与显卡和声卡、输入设备等进行交互。如果没有这组标准API函数库,那你就需要为每一种显卡、声卡的每个组合和每种类型的键盘、鼠标和游戏杆编写不同的代码。这不又回到了以前的Dos时代。为了解决这个问题,微软公司推出了DirectX。DirectX从具体的硬件中抽象出来,并且将一组通用指令转换成硬件的具体命令。这样开发语言通过调用统一标准的Direct X函数库就可以操作每一种显卡、声卡的每个组合和每种类型的键盘、鼠标和游戏杆等多媒体了。

102.BI数据可视化工具应该如何选择?
在这里插入图片描述
103.数上开花。数据可视化。

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值