【Visual C++】游戏开发笔记二十七 Direct3D 11入门级知识介绍
游戏开发笔记二十七 Direct3D 11入门级知识介绍
作者:毛星云 邮箱: happylifemxy@163.com 期待着与志同道合的朋友们相互交流
上一节里我们介绍了在迈入DirectX 11的学习旅程之后第一个demo创建的全过程。但由于知识衔接的需要,我们的第一个demo里面涉及到的大部分知识都是关于Win32的。而为了使之前讲解的Blank Win32 Window Demo蜕变成我们期望的Direct3D的模样,我们将在这节的笔记里面对Direct3D的入门级的基础知识做一个详细的介绍,以便在下节笔记里轻车熟路地写出属于我们的第一个完整的Direct3D11 Demo。
入门知识的第一步当然是进行DirectX开发环境的配置,这在笔记二十五里面有详细介绍,详情请移步:
【Visual C++】游戏开发笔记二十五 最简化的DirectX 11开发环境的配置
下面就开始正题,我们将分八个部分对入门级的Direct3D知识进行一个讲解。
一、 Direct3D的初始化
初始化Direct3D,我们需要完成以下四个步骤:
1.定义我们需要检查的设备类型(device types)和特征级别(feature levels)
2.创建Direct3D设备,渲染设备(context)和交换链(swap chain)。
3.创建渲染目标(render target)。
4.设置视口(viewport)
这里只是给大家一个框架的概念,各个部分下面会详细展开讲解。
二、驱动设备类型与特征等级
在Direct3D 11中我们能使用的设备有硬件设备(hardware device),参考设备(reference device),软件驱动设备(software driver device), 以及WARP设备 (WARP device)。
硬件设备(hardware device)是一个运行在显卡上的D3D设备,在所有设备中运行速度是最快的。这将是我们日后讨论最多的一种类型。
参考设备(reference device)是用于没有可用的硬件支持时在CPU上进行渲染的设备。
简言之,参考设备就是利用软件,在CPU对硬件渲染设备的一个模拟。但是不幸的是,这种方式非常的低效,所以在开发过程中,没有其他可用选择的时候,我们才采用这种方式。比如新一代的DirectX发布了,市面上还没有支持这种新版本DirectX的硬件,我们在开发过程中就只能采用这种方式来跑了。
软件驱动设备(software driverdevice)是开发人员自己编写的用于Direct3D的渲染驱动软件。这种方式通常不推荐用于高性能或者对性能要求苛刻的应用程序,下面介绍的WARP设备将是更好的选择。
WARP设备(WARPdevice)是一种高效的CPU渲染设备,可以模拟现阶段所有的Direct3D特性。WARP使用了Windows Vista /Windows 7/Winodws 8中的Windows Graphic 运行库中高度优化过的代码作为支撑,这让这种方式出类拔萃,相比与上文提到的参考设备(reference device)模式更加优秀。WARP设备在配置不高的机器上面可以达到化腐朽为神奇的功效。在我们的硬件不支持实时应用程序(real-time application)的情况下,用WARP设备作为替补是一个明智的选择,因为相比而言,参考设备(reference device)的执行效率实在是无法令人恭维。即便如此,WARP设备的执行效率还是不能和硬件设备同日而语,毕竟它依旧是对硬件的一种模拟,即使这种模拟是非常高效的。
注意:这不是对设备类型一个完整的列举,还有很多细枝末节的设备类型,在这里没必要一一列举
Direct3D的特征等级用于指定需要设定的设备目标。在这个专栏之中,我们将针对三种设备,第一种当然是我们的Direct3D 11设备,第二种为Direct3D 10.1设备,第三种为Direct3D 10.0设备。再这三种设备都无法支持的情况下,我们再选择WARP设备或者参考设备作为后援。
下面贴出来的代码段1为后面我们需要用到的驱动类型和特征级别的一个声明。通过创建各种类型的数组,我们可以使用循环来尝试首先创建我们最需要的设备,然后若执行失败则继续创建其他的设备类型。浅墨记得我们之前提到过,Win32宏ARRAYSIZE能够用来返回一个数组的大小,Win32函数GetClientRect可以用来计算应用程序客户区的大小。算出来的值会用于设置之后的D3D设备渲染的宽度和高度。
另外,需要记住Win32应用程序是分客户区和非客户区的,我们仅能在客户区上进行渲染。
代码段1 指明驱动设备类型和特征等级
RECT dimensions;
GetClientRect( hwnd, &dimensions );
unsigned int width = dimensions.right - dimensions.left;
unsigned int height = dimensions.bottom - dimensions.top;
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,D3D_DRIVER_TYPE_SOFTWARE
};
unsigned int totalDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
unsigned int totalFeatureLevels = ARRAYSIZE( featureLevels );
三、设备与交换链的创建
下一步便是创建一个交换链,交换链在Direct3D中为一个设备渲染目标的集合。每一个设备都有至少一个交换链,而多个交换链能够被多个设备所创建。一个交换目标可以为一个渲染和显示到屏幕上的颜色缓存(在后面会讨论),等等。
通常在游戏中有,有两种颜色缓存,分别叫做主缓存和辅助缓存,他们一起被称为前后台缓存组合。主缓存中的内容(前台缓存)会显示在屏幕上,而辅助缓存(后台缓存)用于绘制下一帧。
渲染的发生非常之快,屏幕的一部分可以在显示器完成显示更新之前,在先前的结果为基础上进行绘制。缓存之间的切换,可以进行一个良性的运作,前台在显示图像,后台正在为前台准备下一刻将要显示的图像,这样做可以避免很多棘手的问题,提高了效率。
这种技术在计算机图形学中叫做双缓冲(doublebuffering),或者叫页面翻转(page flipping)(这种技术我们之前的一系列Win32 GDI demo中使用得比较勤,研究了之前的demo的朋友们应该已经耳濡目染了吧)。一个交换链能拥有一个或者多个这样的缓冲。
代码段2中列出了创建一个交换链的代码。一个交换链的描述用来定义和创建符合我们需要的交换链。
代码段2 对交换链的设置
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory( &swapChainDesc, sizeof( swapChainDesc ) );
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = width;
swapChainDesc.BufferDesc.Height = height;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.Windowed = true;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
这个范例中定义了D3D的多种取样属性,多重取样(Multisampling)是一种用于采样和平衡渲染像素的创建亮丽色彩变化之间的平滑过渡的一种技术。
缓存的使用和交换链的描述有大量的成员需要设置,但这些设置都是非常简单的。缓存的对交换链的使用是设置下DXGI_USAGE_RENDER_TARGET_OUTPUT,以便交换链能够用于输出,或者换句话说,它能被渲染。
下一步是创建渲染上下文,渲染设备,以及我们拥有的交换链描述。D3D设备一般都是设备本身和硬件之间的通信,而D3D上下文是一种描述设备如何绘制的渲染设备上下文,这也包含了渲染状态和其他的绘图信息。
正如我们讨论过的,交换链是设备和上下文将要绘制的渲染目标。
创建设备上下文,渲染上下文和交换链所需的代码在代码段3中详细列出了,.这段代码为下次内容即将展示的Direct3D 11 BlankWindows Demo的一个片段。
代码段3 Direct3D设备,设备上下文,以及交换链的创建
ID3D11Device device_;
ID3D11Context d3dContext_;
IDXGISwapChain swapChain_;
unsigned int creationFlags = 0;
#ifdef _DEBUG
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
HRESULT result;
unsigned int driver = 0;
for( driver = 0; driver < totalDriverTypes; ++driver )
{
result = D3D11CreateDeviceAndSwapChain( 0, driverTypes[driver],0,
creationFlags, featureLevels, totalFeatureLevels,
D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
&d3dDevice_, &featureLevel_, &d3dContext_ );
if( SUCCEEDED( result ) )
{
driverType_ = driverTypes[driver];
break;
}
}
if( FAILED( result ) )
{
DXTRACE_MSG( "Failed to create the Direct3D device!");
return false;
}
交换链,设备和渲染上下文可以在单独的Direct3D函数调用中被创建,或者通过特定对象的Direct3D来调用(例如用CreateSwapChain函数来专门创建一个交换链)。
这个函数为D3D11CreateDeviceAndSwapChain。在代码段2中我们在每个驱动类型中循环,试图创建一个合适得设备,或为一个硬件设备,或为一个WARP设备,抑或一个参考设备(reference device)。因为如果创建失败,我们就无法初始化我们的Direct3D。
D3D11CreateDeviceAndSwapChain函数中包含了特征等级作为其参数, 所以如果至少有一个这样的特征等级存在,而且若我们的设备类型也存在,这个函数才会执行成功。
其中D3D11CreateDeviceAndSwapChain函数具有如下的函数原型:
HRESULT D3D11CreateDeviceAndSwapChain(IDXGIAdapter *pAdapter,D3D_DRIVER_TYPEDriverType,HMODULE Software,UINT Flags,const D3D_FEATURE_LEVEL*pFeatureLevels,UINT FeatureLevels,UINT SDKVersion,const DXGI_SWAP_CHAIN_DESC *pSwapChainDesc,IDXGISwapChain **ppSwapChain,ID3D11Device **ppDevice,D3D_FEATURE_LEVEL*pFeatureLevel,ID3D11DeviceContext**ppImmediateContext
);
四、 创建渲染目标视图
一个渲染目标视图是一个由Output MergerStage读取的D3D资源。为了output merger能渲染一个后台缓存的交换链,我们为其创建一个渲染目标视图。
由于纹理的概念说来话长,目前我们将纹理理解为一副图像就行了,后面中我们将展开讨论纹理的很多细节内容,。交换链的主缓存和辅助缓存为彩色的图像,为了获得它们的指针,我们一般会调用交换链中的函数GetBuffer。
得到指向缓存的指针后,我们调用Direct3D中的函数CreateRenderTargetView,来创建一个渲染目标视图(rendertarget view.)。渲染目标视图含有ID3D11RenderTargetView类型,而CreateRenderTargetView函数将创建我们视图的2D纹理,渲染目标描述,我们创建的ID3D11RenderTargetView的对象地址为其函数变量。将渲染目标描述变量设为空给我们所有的表面的MIP映射水平都为0级,MIP映射水平也将在后面进行详细讨论。
我们完成渲染目标的创建之后,就能够释放指针到交换链的后台缓存了。因为得到了COM对象的一个引用,我们必须调用COM中的Release函数来减少引用的数量。这样做会避免内存的泄露,因为我们不想应用程序退出后,系统仍然保留着这里内存,这将导致系统资源的浪费,而这种浪费是不科学的。
在每次我们想渲染一个特定的渲染目标的时候,必须在所有的绘制的函数调用之前对它进行设置。这个重任就交给了我们的OMSetRenderTarget函数,这个函数隶属于output merger,在之后会讲到。
代码段4 渲染目标视图的创建和绑定
ID3D11RenderTargetView* backBufferTarget_;
ID3D11Texture2D* backBufferTexture;
HRESULT result = swapChain_->GetBuffer( 0, __uuidof(ID3D11Texture2D ),
( LPVOID* )&backBufferTexture );
if( FAILED( result ) )
{
DXTRACE_MSG( "Failed to get the swap chain backbuffer!" );
return false;
}
result = d3dDevice_->CreateRenderTargetView(backBufferTexture, 0,
&backBufferTarget_ );
if( backBufferTexture )
backBufferTexture->Release( );
if( FAILED( result ) )
{
DXTRACE_MSG( "Failed to create the render targetview!" );
return false;
}
d3dContext_->OMSetRenderTargets( 1, &backBufferTarget_, 0);
在代码段4中你会注意到我们采用了一个叫做DXTRACE_MSG的宏。这个宏用作debugging来用。在之后将进行更详细的讲解。
五、 视口
Direct3D中 的一个重点同时也是难点在于创建和设置视口。
视口定义了我们渲染到屏幕上的面积。在单人或者非分割画面的多人游戏中一般都为全屏,所以我们设置视口的宽度和高度即为交换链的宽度和高度。对于分屏游戏,我们可以创建两个视口,一个视口定义在屏幕上方,另一个定义在屏幕下方。为了渲染分屏视口,我们可以分别以两位不同玩家的角度来渲染。
视点的创建由填充D3D11_VIEWPORT函数和设置调用上下文的RSSetViewports函数将其设置到渲染上下文中来完成。RSSetViewports函数需要我们设置的视口数量和视口对象的列举。全屏视口的创建和设置的相关代码在代码段五中有列举,其中X和Y标明左侧和顶部屏幕的位置,最小和最大深度是0到1之间的值,表明了视口深度的最小和最大值。
代码段5 全屏视口的创建和设置
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<float>(width);
viewport.Height = static_cast<float>(height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
d3dContext_->RSSetViewports( 1, &viewport );
六、清除与显示屏幕
渲染到屏幕需要几个不同的步骤。第一步通常是清除相关渲染目标的表面。在大部分游戏中这一步包含了深度缓存等一系列内容。在下一节即将呈现的demo中我们将在本章稍后实施,我们将清除渲染目标视图的颜色缓冲区到一种特定的颜色。这由调用D3D中的ClearRenderTargetView函数来完成。ClearRenderTargetView拥有如下的函数原型:
void ClearRenderTargetView( ID3D11RenderTargetView*pRenderTargetView,
const FLOAT ColorRGBA[4] );
注:目前的大部分商业游戏中在渲染之前清除颜色缓存并不是必须的,因为像天空这样的环境图形要确保每个像素都会被颜色缓存所覆盖着。
ClearRenderTargetView函数以将被清理的渲染目标视图作为其变量。为了清除屏幕,我们设定某种颜色作为我们需要的背景阴影的颜色。这种颜色可以是红色,绿色,蓝色,和透明色Alpha数组中任意指定的0.0到1.0之间的颜色。这里0.0表示强度为0,而1.0表示完全饱满的强度。若对应于字节,1.0对应255。如果为红绿蓝颜色组合都为1.0,则会得到纯白的颜色。下一步就是绘制场景的几何形状了,最后一步是调用交换链的Present函数在屏幕上显示渲染缓冲区的内容。
Present函数具有以下的声明:
HRESULT IDXGISwapChain::Present( UINT SyncInterval, UINT Flags);
对Present函数的参数一个简单的理解:syncinterval 同步间隔,
flags 演示的标志。
在第n个垂直空白之后,Syncinterval能被设置为0,1,2,3,4来显示。垂直空白是当前帧的最后一列更新时间与下一帧的第一列更新时间的时间差。像电脑显示器这样的设备显示更新像素为垂直的,一列一列进行更新的。
Present函数的flags值可被设为0,表示输出到每一个缓冲区,设为DXGI_PRESENT_ TEST时则表示测试时不进行输出,或为DXGI_PRESENT_DO_ NOT_SEQUENCE表示不进行排序地利用垂直空白同步输出来显示输出。为达到预期的目的,我们可以只是传递0到Present函数来显示我们的渲染结果。
代码段五 展示了一个清屏和显示视图的例子。在后面我们将深入探究颜色缓存,深度存,使画面流畅无比的双缓冲等等。
代码段6 清除渲染目标然后显示显得渲染场景
loat clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
d3dContext_->ClearRenderTargetView( backBufferTarget_,clearColor );
swapChain_->Present( 0, 0 );
七、关于格式
有时候我们需要创建指定的DXGI格式。格式可以用于描述一张图像的布局,每种颜色的位数,或者顶点缓存的布局(后面会讲到)。大多数情况下,DXGI格式用于描述交换链中的顶点布局。
举个例子,DXGI_FORMAT_R8G8B8A8_UNORM,它表示我们定义的每一个RGBA组成部分的数据都为8位。
没指名类型的格式我们称作无类型格式(typeless formats)。他们为每个部分保存相同的位数,但是并不注重包含了什么类型的数据。如DXGI_FORMAT_R32G32B32A32_TYPELESS。常用的清单类型在下面中列出了。
常用的数据格式类型清单:
DXGI_FORMAT_R32G32B32A32_TYPELESS 128位RGBA无类型格式
DXGI_FORMAT_R32G32B32A32_FLOAT 128位RGBA浮点型格式
DXGI_FORMAT_R32G32B32A32_UINT 128位RGBA无符号整型格式
DXGI_FORMAT_R32G32B32A32_SINT 128位RGBA带符号整型格式
DXGI_FORMAT_R8G8B8A8_TYPELESS 32位RGBA无类型格式
DXGI_FORMAT_R8G8B8A8_UINT 32位RGBA无符号整型格式
DXGI_FORMAT_R8G8B8A8_SINT 32位RGBA带符号整型格式
当定义顶点格式的时候,比如DXGI_FORMAT_R32G32B32_FLOAT格式,就是说RGB值都支持是32位的数据类型。有时候,我们会看到特殊的为每一部分指定相同位数的格式,但是他们有不同的扩展名。
举个例子,DXGI_FORMAT_R32G32B32A32_FLOAT 和DXGI_FORMAT_R32G32B32A32_UINT类型的各个部分的位数都是相同的,不同的各个位数上一个是32位的浮点型,一个是32位的无符号整型。
八、 善后工作
Direct3D应用程序中要做的最后一件事情,就是清除和释放我们创建的对象。举个例子,在应用程序开头,我们要创建一个D3D的设备,一个D3D的渲染上下文,一个交换链,以及一个要渲染的目标。当这个应用程序关闭的时候,我们需要释放这些对象,以将这些资源返还给系统。
COM对象保持一个引用计数,告知系统什么时候从内存中移除这些对象是安全的。通过运用Release函数,我们减少了一个对象的引用数量。当引用数量达到0,系统便会回收这些资源。
下面是一个释放D3D对象的范例。用首先用if条件句来确保对象不为null,然后调用Release函数。通常我们以和创建时相反的顺序来释放这些对象。
代码段7 释放Direct3D 11 main对象
if( backBufferTarget_ )backBufferTarget_->Release( );
if( swapChain_ ) swapChain_->Release( );
if( d3dContext_ ) d3dContext_->Release( );
if( d3dDevice_ ) d3dDevice_->Release( );
心得:在释放对象前,我们经常通过检查来确保DirectX对象不为null。因为试图释放一个非法的指针是非常不科学的,这会使我们游戏程序的稳定性荡然无存,经常各种无故崩溃。
本篇文章到这里就结束了,谢谢欣赏。
感谢一直支持【Visual C++】游戏开发笔记系列专栏的朋友们。
【Visual C++】游戏开发 系列文章才刚刚展开一点而已,因为游戏世界实在是太博大精深了~
但我们不能着急,得慢慢打好基础。做学问最忌好高骛远,不是吗?
浅墨希望看到大家的留言,希望与大家共同交流,希望得到睿智的评论(即使是批评)。
你们的支持是我写下去的动力~
精通游戏开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。
大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~
如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨相关的问题。
最后,谢谢你们一直的支持~~~
——————————浅墨于2012年7月1日
转载于:https://blog.51cto.com/8241237/1349404
相关文章:

英特尔蚕食AMD和NVIDIA?
作者 | Daniel Newman译者 | 苏本如,责编 | 郭芮转载自CSDN(ID:CSDNnews)【编者按】一个鲜为人知的事实是,英特尔凭借其在集成显卡上的领先地位,持续占据着电脑显卡市场的头把交椅。但是随着过去两年中首席…

使用phpStudy运行伊人集项目
1.首次运行时,需要把system/config/install.look.php以及system/config/database.php(后面这个文件可以先不删除,若是安装过程中数据库报错,再来删除它)删除2.若只有一个项目版本需要运行的话,可以把项目拷…

【FFmpeg】函数详解(三)
FFmpeg函数详解 14、av_write_frame15、av_interleaved_write_frame16、av_write_trailer17、avio_close18、av_image_get_buffer_size19、av_image_fill_arrays20、av_rescale_q21、视频格式尺寸转换22、音频重采样:23、将像素格式由索引值转换成字符串24、MD5相关25、avio_h…

php时区问题导致php页面显示不正常
cacti安装成功,但报时区错误,已经做了如下操作,后来发现如上设置还是有此问题 将 /usr/local/php5/php.ini文件内修改如下 date.timezone asia/Chongqing 遂解决之。 转载于:https://blog.51cto.com/itnihao/916148

【FFmpeg】降低转码延迟方法、打印信息详解、refcounted_frames详解
文章目录 1、FFmpeg降低转码延迟方法2、ffmpeg打印信息:源码里打印的这段是这样定义的3、解码时 refcounted_frames 标志的使用3.1 启动该标志3.2 解码后,记得释放3.3 详解1、FFmpeg降低转码延迟方法 关闭sync-lookahead降低rc-lookahead,但别小于10,默认是-1降低threads(比…

速度提升270倍!微软和浙大联合推出全新语音合成系统FastSpeech
作者 | 谭旭转载自微软研究院AI头条(ID: MSRAsia)【编者按】目前,基于神经网络的端到端文本到语音合成技术发展迅速,但仍面临不少问题——合成速度慢、稳定性差、可控性缺乏等。为此,微软亚洲研究院机器学习组和微软&a…

Linux —— 目录(文件夹)及文件相关处理指令
可参考这篇文章:https://mp.weixin.qq.com/s?__bizMzU4MTU3OTI0Mg&mid2247484269&idx1&sn38869a1df48d8cdb6278518b51601ce0&chksmfd443be8ca33b2fe937531e061c406786f0e587d8ab10ff15594442265658d08cd8271ae52c5&mpshare1&scene23&s…

工业级3G路由器
宏电工业级3G路由器的特点,工业级标准设计,适应零上60度的高温,零下30度的低温,存工业级制造工艺,适应交通,环保,矿山,电力等工业级应用,欢迎来电索取解决方案,沈阳宏电办事处 刘冰 15940556464 024-31296279 限东三省地区.转载于:https://blog.51cto.com/lbing/916441

【FFmpeg】AVOutputFormat/AVInputFormat 成员变量 flags 总结
1、分类 AVOutputFormat中flags允许的值: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVEAVInputFormat中flags允许的值…

基础必备 | Python处理文件系统的10种方法
作者 | Jeff Hale 译者 | 风车云马;责编 | Jane,Rachel出品 | Python大本营(ID:pythonnews)【导读】在编写一些Python程序的时候,我们常常需要与文件系统进行交互。在本文中,营长为大家整理了10…

安装Oracle11g先决条件检查失败
体系结构 - 此先决条件将测试系统是否具有认证的体系结构。预期值:?N/A实际值:?N/A?错误列表:?-?PRVF-7536 : 无法在节点 "mywin7" 上执行体系结构检查 ?- Cause:? 无法确定系统体系结构。 ?-Action:? 确保正在使用正确的软件包。 处理 转载于:https://www.…

Windows Forms高级界面组件-使用状态栏控件
状态栏(StatusStrip)控件通常显示在窗体的底部,向用户提供有关应用程序状态的信息。如Word应用程序使用状态栏提供页码、行数和列数的信息。StatusStrip派生于ToolStrip,通常由ToolStripStatusLabel对象组成,用于显示指…

【Qt】在QtCreator中编译log4cplus
在QtCreator中编译log4cplus 一、在QtCreator中配置cmake二、编译log4cplus1、下载2、编译、安装一、在QtCreator中配置cmake 参见博客:https://blog.csdn.net/u010168781/article/details/107613606 log4cplus使用cmake来编译,因此需要QtCreator支持cmake 二、编译log4cpl…

IEEE“撑不住”了?声明解除对华为评审限制
整理 | 琥珀出品 | AI科技大本营(ID:rgznai100)6 月 2 日,IEEE 官方发表声明表示:经美国商务部就出口管制条例在 IEEE 出版活动中的适用性做出的说明,华为及其子公司的员工可以参加 IEEE 出版过程的同行评审和编辑工作…

关于软件产业的两个契机
软件产业是一个产业 , 和其它的产业一样 , 有各种角色分工 。 未来的软件是跨行业的 。 未来 , 软件会将各个行业联系在一起 。 云计算是第一代互联网发展到成熟的标志 。 网格计算是第二代互联网的开始 。 软件产业 在 未来 会 分为 平台&a…

java继承中的一些该注意的问题
关于继承,我想大多数人都知道,它是面向对象语言中的三大特性之一,所以在这里,关于继承的概念等我就不做详细介绍了,我主要就讲一下大家对他的认识中一些比较容易犯的错误吧。 错误认识1、继承,是将父类中所…

【C】printf warning: unknown conversion type character ‘l‘ in format [-Wformat=]
1、问题描述 在使用printf、fprintf打印long long类型时报错 printf warning: unknown conversion type character l in format [-Wformat=]2、原因分析 “%lld” 和 “%llu” 是 linux 下 gcc/g++ 用于 long long int 类型 (64 bits) 输入输出的格式符。 而 “%I64d” 和 “…

史上最强最贵Mac Pro诞生,iPadOS和iOS分家!WWDC19全面总结
作者 | 俞佳兴、胡巍巍转载自CSDN(ID:CSDNnews)图片&视频 | 余佳兴摄自美国圣何塞WWDC现场一年一度的WWDC终于来了!43岁的苹果,产品经验位居世界前列。一个迈入中年的公司,该如何持续做出让人惊艳的产品…

Java 抽象类与接口的区别
接口和抽象类有什么区别 你选择使用接口和抽象类的依据是什么? 接口和抽象类的概念不一样。接口是对动作的抽象,抽象类是对根源的抽象 抽象类表示的是,这个对象是什么。接口表示的是,这个对象能做什么。比如,男人&…

XMOVE3.0手持终端——软件介绍(五):在2KB内存的单片机上实现的T9中文输入法
编者注: X-MOVE是作者在业余时间于2010年6月份启动的以运动传感开发,算法和应用的平台,目前已经发展了三个版本,第四版的开发接近尾声。发布在博客园仅为交流技术,不存在商业目的,作者保留一切权利。 一. 综…

推荐系统遇上深度学习,9篇阿里推荐论文汇总!
作者 | 石晓文转载自小小挖掘机(ID: wAIsjwj)业界常用的推荐系统主要分为两个阶段,召回阶段和精排阶段,当然有时候在最后还会接一些打散或者探索的规则,这点咱们就不考虑了。前面九篇文章中,有三篇是召回阶…

ReSharper修改命名风格
默认情况下,ReSharper会建议你全局变量命名使用下划线开头,且第一个字母小写。否则,会给你标记出来,如下: 但我个人不喜欢这种风格,一般使用首字母大写且不带下划线,可以通过配置来调整…

【Qt】Log4Qt(一)下载、编译
Log4Qt(一)下载、编译 1、下载2、编译2.1 单独编译成库2.2 将源码添加到项目中2.2.1 log4qt.pri分析2.2.2 pro示例如下1、下载 github上星最多的是这个:https://github.com/MEONMedical/Log4Qt 下载log4qt最新(截止2021-12-04)的稳定版本v1.5.1(Qt版本需要Qt5.7.0以上)…

android:退出程序
http://kofi1122.blog.51cto.com/2815761/703751 使用的是定义全局变量的方法

ubuntu中使用apt命令安装ipython失败解决方案
在最近使用ubuntu安装ipython时,出现如下报错: 出现这个问题,主要是因为apt还在运行,故解决方案为: 1、找到并且杀掉所有的apt-get 和apt进程 运行下面的命令来生成所有含有 apt 的进程列表,使用ps和grep命…

【Qt】Log4Qt(二)使用
Log4Qt(二)使用 1、使用TTCCLayout 格式化输出1.1 添加头文件1.2 配置根记录器的输出格式1.3 注册记录器,并输出日志2、最简代码3、将日志写入文件4、使用配置文件:log4qt.properties5、使用配置文件:QSettings6、周期性生成日志文件7、滚动生成日志文件(可以指定日志文件…

B站超全分享!2万人收藏的免费计算机科学速成课
整理 | 一一出品 | AI科技大本营(ID:rgznai100)作为一枚程序员,很多人可能都不太能清晰地说出计算机发展脉络,要想成为优秀的程序员,只会编程是不够的。“读史使人明智”,我们还要了解计算机理论知识&#…

图说:Windows 8使用搜索,快速开启应用
在Windows 8中,“开始菜单”变成的“开始屏幕”,想快速找到需要的应用不是件容易的事,毕竟桌面可以安装太多的应用。 怎么快速找到需要的应用的,其实方法也非常简单,只需在“开始屏幕”下使用键盘,键入需要…

一个可以卷起来的蓝牙键盘,简直是办公码字神器!
作为一个办公室码字党,熊大大一直觉得ipad最大的bug就是码字不方便。以前,我每次码字都会把平板先平放,打字才能顺手╮(╯﹏╰)╭后来买了蓝牙键盘,码字方便了,但键盘又大又厚重,日常携带巨不方…

比较v-bind和v-model
简单来说,区别如下:1.v-bind用来绑定数据和属性以及表达式,缩写为:2.v-model使用在表单中,实现双向数据绑定的,在表单元素外使用不起作用 一、v-model v-model多在表单中使用,在表单元素上创建双…