一、背景

喔,五天的实训终于结束了,学校安排的这次实训课名称叫高级程序设计实训,但在我看来,主要是学习了Visual C++ .NET所提供的MFC(Microsoft Foundation Class)库所提供的类及其功能函数的使用。写这一篇博客的目的是针对实训中出现的问题做一些说明,方便以后查看,并且对这次实训做一些总结。这一次的实训对我来说其实挺难受的,真正用来学习使用VS和MFC的时间只有三天,加上下个周是考试周,还有几门课没有复习完,这几天基本上是连轴转,中午也泡在实验室里,唉啊还是自己太菜了。最后我们需要提交一个课程设计程序,因为时间的原因,我选择了最简单的图形界面编辑工具,这个程序其实在C++的课程设计上就有这个,但当时我还不会windows图形界面的编程,现在想想这两个课程设计其实完全可以是一份(捂脸)。
最后做出来的界面是这样的:

在功能上:

  1. 能够在windows的界面下画图,能够画直线、空心矩形、、圆角矩形、空心圆形、填充矩形、填充圆形、填充圆角矩形和文字。
  2. 能够改变画图是画笔用的颜色、线宽、线型和填充用的颜色、字体。
  3. 能够保存、打开所做的图形文件
  4. 拥有菜单、工具栏、鼠标右键等编辑界面。

二、程序说明

1.工具栏说明

2.画图菜单


在画图菜单下,能够选择画直线、空心矩形、空心圆形、空心圆角矩形、填充矩形、填充圆形、填充圆角矩形。

3.文本菜单


文本输入菜单下有两个选项一个是文本输入、一个是字体设置,分别对应着两个对话框。

文本输入对话框,能够根据指定的x、y横纵坐标来定位输入位置,打印输入的相应信息。

而字体设置,调用系统自带的对话框,完成对字体类型、字形和字体大小的设置。

4.画笔设置菜单


画笔设置菜单下有画笔颜色、画笔类型、画笔宽度三个选项。其中画笔类型又包含实线、虚线、点线、点划线、双点划线五个选项。画笔类型根据查阅课本内容和上网搜索得知,只有在宽度为1的时候,才能显示除实线外的其他画笔类型,当宽度大于1时画出来的都是实线类型的线条。

颜色设置,调用系统自带的对话框,完成对画笔、画刷颜色的选择。同时选用该对话框能够实现自定义颜色。

画笔宽度设置对话框是自己设置的对话框,输入相应的画笔宽度,实现画笔宽度的改变。

5.界面下鼠标右键


右击鼠标会有鼠标右键菜单,其功能选项与功能栏所给的功能是一样的,选择画直线、空心矩形、空心圆形、空心圆角矩形、填充矩形、填充圆形、填充圆角矩形和文本。

三、鼠标拖动绘画

该程序的基础功能就是能够拖动鼠标来绘制图形,这里面实际上用到的是橡皮筋技术。在鼠标拖动中,每当鼠标的位置发生了改变,需要清除已经绘制的线段,课本已经该出了实现该过程的代码。当然之前需要在视图View类中添加鼠标左键按下,鼠标移动,鼠标左键抬起的消息映射。

void CShirrView::OnLButtonDown(UINT nFlags, CPoint point)
{
//将鼠标左键按下位置存储到p1、p2
p1 = p2 = point;
b=true; //设置绘图标志
pdc->SetROP2(R2_NOTXORPEN);//设置绘图模式为R2_NOTXORPEN,注意背景为白色
CView::OnLButtonDown(nFlags, point);
}
void CShirrView::OnMouseMove(UINT nFlags, CPoint point)
{
if (!b)
return; //如果不是绘图状态,返回 //P1为鼠标左键按下位置,P2为鼠标上次位置
//即按前次位置重绘了一次,模式是R2_NOTXORPEN
//最终效果是白色,由于底色为白,实际效果是清除了上次的线段
pdc->MoveTo(p1.x,p1.y);
pdc->LineTo(p2.x,p2.y); p2 = point;
//p1仍为鼠标左键按下位置,P2为当前鼠标位置
pdc->MoveTo(p1.x,p1.y);
pdc->LineTo(p2.x,p2.y); //从P1到鼠标当前位置绘制线段
CView::OnMouseMove(nFlags, point);
}
void CShirrView::OnLButtonDown(UINT nFlags, CPoint point)
{
//将鼠标左键按下位置存储到p1、p2
p1 = p2 = point;
b=true; //设置绘图标志
pdc->SetROP2(R2_NOTXORPEN);//设置绘图模式为R2_NOTXORPEN,注意背景为白色
CView::OnLButtonDown(nFlags, point);
}
void CShirrView::OnMouseMove(UINT nFlags, CPoint point)
{
if (!b)
return; //如果不是绘图状态,返回 //P1为鼠标左键按下位置,P2为鼠标上次位置
//即按前次位置重绘了一次,模式是R2_NOTXORPEN
//最终效果是白色,由于底色为白,实际效果是清除了上次的线段
pdc->MoveTo(p1.x,p1.y);
pdc->LineTo(p2.x,p2.y); p2 = point;
//p1仍为鼠标左键按下位置,P2为当前鼠标位置
pdc->MoveTo(p1.x,p1.y);
pdc->LineTo(p2.x,p2.y); //从P1到鼠标当前位置绘制线段
CView::OnMouseMove(nFlags, point);
}

上面的代码是用来画直线的,能够完成画直线的功能,那么就可以照猫画虎实现画矩形、画圆的功能了,这些图形都需要起点和终点的坐标作为画图的参数。

同时我们要明白鼠标相应这些函数是在当前视图中执行的,也就是说,我们一打开该程序,只要在视图中点击移动鼠标,这些函数其实都会相应执行到,那么我们该怎么去设计选择不同的图形?

其实这很简单,改造鼠标移动消息相应函数和鼠标左键抬起消息响应函数即可!我们可以给不同的图形一个编号,按下选择图形的按钮后,相对应的消息相应函数就会改变那个编号,鼠标移动消息相应函数和鼠标左键抬起消息响应函数根据这个编号来绘制不同的图形就可以了!

那鼠标左键按下消息响应函数不用去改造吗?

是不用改造的,因为鼠标一开始按下只是为了获取起点的坐标,而是不去画图形,所以这个对所有的图形都适用。

在这之前需要记录好每一个选择图形按键的ID,和消息响应函数,同时在消息响应函数中完成了CDC对象指针pdc的构造。

/*
1 画直线
2 画矩形
3.画空心圆形
4.画填充矩形
5.画填充圆形
6.画圆角矩形
7.画填充圆角矩形
直线 ID_LINE,
矩形 ID_RECTANGLE
圆形 ID_CIRCLE
填充矩形 ID_TRECTANGLE
填充圆形 ID_TCIRCLE
圆角矩形 ID_YTRECTANGLE
填充圆角矩形 ID_TYTRECTANGLE
*/
void CWkfDrawingView::OnLine()
{
// TODO: 在此添加命令处理程序代码
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
} void CWkfDrawingView::OnRectangle()//画矩形
{
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
}
void CWkfDrawingView::OnCircle()//画空心圆形
{
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
}
void CWkfDrawingView::OnTrectangle()
{
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
} void CWkfDrawingView::OnTcircle()
{
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
}
void CWkfDrawingView::OnYtrectangle()
{
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
} void CWkfDrawingView::OnTytrectangle()
{
MyDrawStyle = ;
pdc=new CClientDC(this);//构造对象
b=false;
}

下面给出鼠标按下消息相应函数、鼠标移动消息相应函数和鼠标左键抬起消息响应函数的代码,MyStart 和MyEnd是视图类的两个CPoint类型的成员变量,用来保存起点和终点的坐标。

void CWkfDrawingView::OnLButtonDown(UINT nFlags, CPoint point)//鼠标按下
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
MyStart = MyEnd = point;
pdc=new CClientDC(this);
pdc->SetROP2(R2_NOTXORPEN);
b = true;
CView::OnLButtonDown(nFlags, point);
}
void CWkfDrawingView::OnMouseMove(UINT nFlags, CPoint point)//鼠标移动
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
/*pdc->MoveTo(MyStart.x,MyStart.y);
pdc->LineTo(MyEnd.x,MyEnd.y);*/
if(!b)
return ;
CPen pen(GP.type, GP.width, GP.pencolor);
OldPen=pdc->SelectObject(&pen);
if(MyDrawStyle==)
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->MoveTo(MyStart.x,MyStart.y);
pdc->LineTo(MyEnd.x,MyEnd.y);
MyEnd=point;
pdc->MoveTo(MyStart.x,MyStart.y);
pdc->LineTo(MyEnd.x,MyEnd.y);
}
else if(MyDrawStyle==)
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->Rectangle(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
MyEnd = point;
pdc->Rectangle(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
}
else if(MyDrawStyle==)
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->Ellipse(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
MyEnd = point;
pdc->Ellipse(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
}
else if(MyDrawStyle==)
{
//pdc->SelectObject(&newBrush);
CBrush bsh;
bsh.CreateSolidBrush(GP.pencolor);
pdc->SelectObject(&bsh);
pdc->Rectangle(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
MyEnd = point;
pdc->Rectangle(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
bsh.DeleteObject();
}
else if(MyDrawStyle==)
{
//pdc->SelectObject(&newBrush);
CBrush bsh;
bsh.CreateSolidBrush(GP.pencolor);
pdc->SelectObject(&bsh);
pdc->Ellipse(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
MyEnd = point;
pdc->Ellipse(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
bsh.DeleteObject();
}
else if(MyDrawStyle==)
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->RoundRect(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y,a.x,a.y);
MyEnd = point;
pdc->RoundRect(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y,a.x,a.y);
}
else if(MyDrawStyle==)
{
CBrush bsh;
bsh.CreateSolidBrush(GP.pencolor);
pdc->SelectObject(&bsh);
pdc->RoundRect(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y,a.x,a.y);
MyEnd = point;
pdc->RoundRect(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y,a.x,a.y);
bsh.DeleteObject();
}
CView::OnMouseMove(nFlags, point);
}
void CWkfDrawingView::OnLButtonUp(UINT nFlags, CPoint point)//鼠标抬起
{
GPen g;
g.start = MyStart;
g.end = MyEnd;
g.width = MyWidth;
g.type = type;
g.style = MyDrawStyle;
g.pencolor = GP.pencolor;
if(MyDrawStyle==)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
pdc->SetROP2(R2_COPYPEN);//当前颜色覆盖背景颜色
pdc->MoveTo(MyStart.x,MyStart.y);
pdc->LineTo(point.x,point.y);
g.c = GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
else if(MyDrawStyle==)
{
pdc->SetROP2(R2_COPYPEN);
pdc->Rectangle(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
g.c = GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
else if(MyDrawStyle==)
{
pdc->SetROP2(R2_COPYPEN);
pdc->Ellipse(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
g.c = GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
else if(MyDrawStyle==)
{ //pdc->SelectObject(&newBrush);
CBrush bsh;
bsh.CreateSolidBrush(GP.pencolor);
pdc->SetROP2(R2_COPYPEN);
pdc->SelectObject(&bsh);
pdc->Rectangle(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
g.c =GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
else if(MyDrawStyle==)
{ //pdc->SelectObject(&newBrush);
CBrush bsh;
bsh.CreateSolidBrush(GP.pencolor);
pdc->SetROP2(R2_COPYPEN);
pdc->SelectObject(&bsh);
pdc->Ellipse(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y);
g.c =GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
else if(MyDrawStyle==)
{ pdc->SetROP2(R2_COPYPEN);
pdc->RoundRect(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y,a.x,a.y);
g.angle=a;
g.c = GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
else if(MyDrawStyle==)
{
//pdc->SelectObject(&newBrush);
CBrush bsh;
bsh.CreateSolidBrush(GP.pencolor);
pdc->SetROP2(R2_COPYPEN);
pdc->SelectObject(&bsh);
pdc->RoundRect(MyStart.x,MyStart.y,MyEnd.x,MyEnd.y,a.x,a.y);
g.angle=a;
g.c = GP.pencolor;
b=false;//解除绘图关系
CView::OnLButtonUp(nFlags, point);
}
GetDocument()->Mylist.AddTail(g);//保存信息
Invalidate();
}

上面的代码中也嵌入了画笔和画刷的内容,画笔和画刷有一个特性就是一旦被定义和创建后,之后所绘制的图形就会之间用上了,所以要注意画笔和画刷的使用,而填充图形和空心图形的区别就是有没有画刷。

CBrush bsh;//定义画刷
bsh.CreateSolidBrush(GP.pencolor);//创建画刷
pdc->SelectObject(&bsh);//选择画刷

画笔的使用

CPen pen(GP.type, GP.width, GP.pencolor);//画笔的定义和创建,三个参数画笔的类型、画笔宽度、画笔的颜色
pdc->SelectObject(&pen);//选择画笔

上面还有一些代码是关于图形保存和重绘的,之后进行说明。

四、文件保存和读取——文档串行化

文档类中中提供了文档串行化(Serialize)函数能够将对象当前的状态由成员变量的值表示写入硬盘中,下次再从硬盘中读取对象的状态,从而重建对象。

但在这里的对象是什么呢?

是图形,可是图形的种类很多,如果将每一个图形的信息都通过结构体定义出来,那么会有很多的结构体来表示不同的图形,这里我选择了一种方法,将所有图形的参数,不管是特有的参数还是共有的参数,都统统封装到一个结构体中,为这个结构体创建链表,修改串行化函数就可以了!

//为了让视图和文档都认识GPen这个存储图片信息的结构体,需要在Stdafx.h中添加代码
struct GPen//保存画笔参数全局变量
{
int type;//画笔类型
int width;//画笔宽度
COLORREF pencolor;//画笔颜色
COLORREF c;
CPoint start,end;//直线、矩形和椭圆的起始点
int style;//图形的类型
CPoint angle;//圆角矩形角度
};

为文档Doc类添加Gpen的链表:

CList <GPen,GPen> Mylist;

文档类的串行化Serialize函数:

void CWkfDrawingDoc::Serialize(CArchive& ar)
{
int i;
if (ar.IsStoring())//保存
{
// TODO: 在此添加存储代码
ar<<Mylist.GetCount();
GPen g;
POSITION pos = Mylist.GetHeadPosition();
for(i = ; i<Mylist.GetCount(); i++)
{
g = Mylist.GetNext(pos);
ar<<g.type<<g.width<<g.pencolor<<g.c<<g.start<<g.end<<g.style<<g.angle;
} }
else//读取
{
// TODO: 在此添加加载代码
int count;
ar>>count;
GPen g;
POSITION pos = Mylist.GetHeadPosition();
for(i = ; i<count; i++)
{
ar>>g.type>>g.width>>g.pencolor>>g.c>>g.start>>g.end>>g.style>>g.angle;
Mylist.AddTail(g);
}
}
}

打开之前保存文件需要有一个重绘函数,我们之前画图都只是在鼠标移动和鼠标左键抬起的时候画图,现在画图都要在视图类中的OnDraw中重绘了,这也就是之前的鼠标左键抬起消息响应函数中,最后需要将所画的图形信息保存到链表中的原因了。(鼠标抬起了,这个图形才真正被画出来)

GetDocument()->Mylist.AddTail(g);//保存信息
Invalidate();

之后的哪一行代码就是刷新,去执行OnDraw函数了。

void CWkfDrawingView::OnDraw(CDC* pDC)//加载文件重绘函数
{
int i;
CWkfDrawingDoc* pDoc = GetDocument();
pdc=new CClientDC(this);
ASSERT_VALID(pDoc);
if (!pDoc)
return;
GPen g;
POSITION pos = pDoc->Mylist.GetHeadPosition();
for(i = ; i<pDoc -> Mylist.GetCount(); i++)
{
g = pDoc -> Mylist.GetNext(pos);
CPen p(g.type,g.width,g.pencolor);
pdc->SelectObject(&p);
pdc->MoveTo(g.start.x,g.start.y);
if(g.style==)//画直线
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->LineTo(g.end.x,g.end.y);
}
if(g.style==)//画矩形
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->Rectangle(g.start.x,g.start.y,g.end.x,g.end.y);
}
if(g.style==)//画圆形
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->Ellipse(g.start.x,g.start.y,g.end.x,g.end.y);
}
if(g.style==)//画填充矩形
{
CBrush bsh;
bsh.CreateSolidBrush(g.pencolor);
pdc->SelectObject(&bsh);
pdc->Rectangle(g.start.x,g.start.y,g.end.x,g.end.y);
bsh.DeleteObject();
}
if(g.style==)//画填充圆形
{
CBrush bsh;
bsh.CreateSolidBrush(g.pencolor);
pdc->SelectObject(&bsh);
pdc->Ellipse(g.start.x,g.start.y,g.end.x,g.end.y);
bsh.DeleteObject();
}
if(g.style==)//画圆角矩形
{
pdc->SelectStockObject(NULL_BRUSH);
pdc->RoundRect(g.start.x,g.start.y,g.end.x,g.end.y,g.angle.x,g.angle.y);
}
if(g.style==)//画填充圆角矩形
{
CBrush bsh;
bsh.CreateSolidBrush(g.pencolor);
pdc->SelectObject(&bsh);
pdc->RoundRect(g.start.x,g.start.y,g.end.x,g.end.y,g.angle.x,g.angle.y);
bsh.DeleteObject();
}
pdc->SelectObject(OldPen);
}
}

五、几个对话框

颜色对话框和字体对话框是系统给的,我这里给出其按键的消息响应函数。其中的MyFont和是Pcolor是视图类的两个成员变量CFont MyFont COLORREF Pcolor

void CWkfDrawingView::OnFont()//字体设置
{
CFontDialog dlg;
if(IDOK==dlg.DoModal())
{
if(MyFont.m_hObject)
{
MyFont.DeleteObject();
}
MyFont.CreateFontIndirect(dlg.m_cf.lpLogFont);//字体信息
MyFontName=dlg.m_cf.lpLogFont->lfFaceName;//字体的名称
}
}
void CWkfDrawingView::OnPancolor()//画笔颜色设置
{
CColorDialog dlg(,CC_FULLOPEN);
if(dlg.DoModal())
{
Pcolor = dlg.GetColor();//从颜色对话框中获取颜色信息
GP.pencolor=Pcolor;
}
else if(dlg.DoModal()==IDCANCEL)
{}
}

对于自定义的对话框,有画笔的宽度设置,画笔类型设置,文本输入,代码如下:

void CWkfDrawingView::OnTxt()//文本输入
{
// TODO: 在此添加命令处理程序代码
CTxtlog dlg;
if(dlg.DoModal()==IDOK)
{
int X=dlg.MyX;
int Y=dlg.MyY;
CString String=dlg.MyString;
pdc=new CClientDC(this);//构造对象
pdc->SetTextColor(GP.pencolor);//设置文件颜色
pdc->SelectObject(&MyFont);
pdc->TextOut(X,Y,String);
}
else if(dlg.DoModal()==IDCANCEL)
{}
} void CWkfDrawingView::OnLineW()//画笔宽度
{
// TODO: 在此添加命令处理程序代码
CLWidth dlg;
if(dlg.DoModal()==IDOK)
{
GP.width=dlg.width;//更新画笔的宽度
MyWidth=dlg.width;
}
else if(dlg.DoModal()==IDCANCEL)
{}
}
/*
PS_SOLID 实线
PS_DASH 虚线
PS_DOT 点线
PS_DASHDOT 点化线
PS_DASHDOTDOT 双点化线
*/ void CWkfDrawingView::OnSolid()//线条类型
{
// TODO: 在此添加命令处理程序代码
type=PS_SOLID;
GP.type=type;
pdc=new CClientDC(this);
}
void CWkfDrawingView::OnDash()
{
// TODO: 在此添加命令处理程序代码
type=PS_DASH;
GP.type=type;
}
void CWkfDrawingView::OnDot()
{
// TODO: 在此添加命令处理程序代码
type=PS_DOT;
GP.type=type;
} void CWkfDrawingView::OnDashdot()
{
// TODO: 在此添加命令处理程序代码
type=PS_DASHDOT;
GP.type=type;
} void CWkfDrawingView::OnDashdotdot()
{
// TODO: 在此添加命令处理程序代码
type=PS_DASHDOTDOT;
GP.type=type;
}

但对于文本输入和字体宽度设置,需要从对话框中获取信息,保存到变量中,这就需要交换函数,在这之前需要将自定义的对话框设置一个对话框类,与对话框资源相关联,所有的代码处理都在对话框类中进行。以文本输入为例,添加文本输入对话框类

#pragma once
// CTxtlog 对话框
class CTxtlog : public CDialog
{
DECLARE_DYNAMIC(CTxtlog) public:
CTxtlog(CWnd* pParent = NULL); // 标准构造函数
virtual ~CTxtlog(); // 对话框数据
enum { IDD = IDD_TEXT }; protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP()
public:
int MyX;
public:
int MyY;
public:
CString MyString;
};

修改其中的数据交换函数为:

void CTxtlog::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, ID_TXTX, MyX);
DDX_Text(pDX, ID_TXTY, MyY);
DDX_Text(pDX, ID_TXTS, MyString);
}
 

MFC图形编辑界面工具的更多相关文章

  1. 【Telerik控件学习】-建立自己的图形编辑工具(Diagram)

    Telerik提供了RadDiagram控件,用于图形元素的旋转,拖拽和缩放.更重要的是,它还拓展了许多绑定的命令(复制,剪切,粘贴,回退等等). 我们可以用来组织自己的图形编辑工具. Step1.定 ...

  2. WPF学习11:基于MVVM Light 制作图形编辑工具(2)

    本文是WPF学习10:基于MVVM Light 制作图形编辑工具(1)的后续 这一次的目标是完成 两个任务. 画布 效果: 画布上,选择的方案是:直接以Image作为画布,使用RenderTarget ...

  3. 了解一下 Linux 上用于的 SSH 图形界面工具

    如果你碰巧喜欢好的图形界面工具,你肯定很乐于了解一些 Linux 上优秀的 SSH 图形界面工具.让我们来看看这三个工具,看看它们中的一个(或多个)是否完全符合你的需求. 在你担任 Linux 管理员 ...

  4. MAPZONE GIS SDK接入Openlayers3之五——图形编辑工具

    图形编辑工具提供对要素图形进行增.删.改的功能,具体包括以下几种工具类型: 浏览工具 选择工具 创建要素工具 删除命令 分割工具 合并命令 节点编辑工具 修边工具 撤销命令 重做命令 工具的实现基本上 ...

  5. WPF学习12:基于MVVM Light 制作图形编辑工具(3)

    本文是WPF学习11:基于MVVM Light 制作图形编辑工具(2)的后续 这一次的目标是完成 两个任务. 本节完成后的效果: 本文分为三个部分: 1.对之前代码不合理的地方重新设计. 2.图形可选 ...

  6. Ubuntu 16.04安装7zip的图形界面工具PeaZip

    其实PeaZip不是7zip的图形界面工具,而是一整套方案,里面包括了7z格式的解压缩等. PeaZip Linux版本只有32位包,如果你使用的是64位Ubuntu系统,那么先打开终端运行下面的命令 ...

  7. 纯小白安装MongoDB的图形界面工具adminMongo

    今天安了两个MongoDB的图形界面工具,robot3和adminMongo,至于为什么安两个....因为网上说啥好用的都有,我也很迷... 安装adminMongo的时候...和正常软件安装流程不太 ...

  8. swing开发图形界面工具配置(可自由拖控件上去)

    swing开发图形界面工具,eclipse swing图形化操作界面工具配置 1.有一个小功能要有一个界面,之前知道有一个 图形化界面的(就是可以往上面拖控件布局的工具)JBuilder,今天上午就下 ...

  9. MFC-创建MFC图形界面dll

    创建MFC图形界面dll 概述: 利用MFC的DLL框架,制作带有图形界面的dll,可以实现很多功能. 流程: 选择静态链接MFC DLL:以免有的库没有. 采用该框架创建的MFC,会自动生产一个MF ...

随机推荐

  1. LinuxMint配置GitHub(图文教程)

    1.生成秘钥(直接回车,秘钥存放路径看命令行信息) 2.打开秘钥,需要注意的是.ssh可能是隐藏的,这时需要Ctrl+H显示隐藏文件夹 3.复制秘钥,添加到GitHub(Settings), 4.添加 ...

  2. 小程序 wx.request请求

    1.wx.request相当于发送ajax请求 微信官方解释 参数 属性 类型 默认值 必填 说明 url string 是 开发者服务器接口地址 data string/object/ArrayBu ...

  3. NET Framework项目移植到NET Core上遇到的一系列坑(2)

    目录 获取请求的参数 获取完整的请求路径 获取域名 编码 文件上传的保存方法 获取物理路径 返回Json属性大小写问题 webconfig的配置移植到appsettings.json 设置区域块MVC ...

  4. EXT grid单元格点击时判断当前行是否可编辑

    var c_gridColumns = new Ext.grid.ColumnModel({ columns: [//列模式 c_sm, { header: "内码", dataI ...

  5. JS---BOM---定时器

    定时器 参数1:函数 参数2:时间---毫秒---1000毫秒--1秒 执行过程: 页面加载完毕后, 过了1秒, 执行一次函数的代码, 又过了1秒再执行函数..... 返回值就是定时器的id值   v ...

  6. composer入门 一些简单常用的命令介绍

    composer是什么 composer是PHP的插件依赖管理工具,我个人感觉和java的Maven.Gradle很类似. Windows OS下安装composer 参考: https://www. ...

  7. Caffeine批量加载浅析

    最近项目中的本地缓存,看是从Guava改成了Caffeine,据说是性能更好,既然性能更好的话,那么就用起来吧.不过在使用过程中,发现了单个load和批量loadall方面的一些小设置,记录一下. 一 ...

  8. springboot + springcloud +nacos实战

    首先从整个软件的功能和应用场景来说,nacos更像consul,而非eureka,nacos设计的时候自带的配置中心功能,让我们省下了去搞springcloud config的时间,但这里并不是说na ...

  9. MySQL 是如何处理死锁的

    MySQL(InnoDB)是如何处理死锁的 一.什么是死锁 官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁. 这个就好比你有一个人质,对方有一个人质,你们俩去 ...

  10. 《C#并发编程经典实例》学习笔记—2.8 处理 async Task 方法的异常

    异常处理一直是所有编程语言不可避免需要考虑的问题,C#的异步方法的异常处理和同步方法并无差别,同样要借助 try catch 语句捕获异常. 首先编写一个抛出异常的方法 static async Ta ...