九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

简单图形编程的学习(1)---文字 (Qt实现)


简单图形编程的学习(1---文字 (Qt实现)

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

一、   全部简单图形编程的学习说在前面的话

      此系列文章均假设读者已经具备一定的对应的程序编写知识,无论是最简单的small basic,还是因为常用而被人熟知的Windows GDI,或者是Linux下用的更多的Qt(一般我用PyQt),甚至是现在国内知道的人并不多的Android,我都不准备讲太多基础的语法,或者与平台相关的太多背景知识,这些靠读者先行学习,我仅仅准备在自己学习的过程中找点乐子:)看看我用一些简单的接口都能想出干什么事情,然后展示给大家看看,图形程序实在是最好展示的一类程序了,不像其他程序一样,哪怕我讲了一堆的boost,真正见识到boost强大的又有几个呢?-_-!要知道,今天起,所有程序都是窗口程序,不再是命令行!!!!人类用了多久才走到这一步我不知道。。。。我用了25.......(从我出生算起)或者1年(从工作开始)

       另外,想要看怎么编写窗口应用程序的就不要走错地方了,这里不是想怎么描述怎么使用一个又一个的控件,这里都是讲绘图的-_-!

 

二、   谈谈Qt

由于今天是第一篇,所以谈谈Qt,Qt原来是奇趣(trolltech)公司的产品,目前奇趣已经被诺基亚收购。很久前学习Linux的时候就知道Qt了(可谓久仰大名,如雷贯耳),最重要的是,Qt以其良好的面向对象特性,可移植性著称,这也是我特别喜欢的特性,所以当年在学习Python并选择一个GUI的时候,综合考虑,最终没有选择PyGTKwxPython等一样优秀的开源产品,(见以前的一篇文章《pyqt学习 的开始,顺便小谈目前gui的选择...而是PyQtQt的原始版本是C++,(但是目前官方已经支持JAVA)而PyQt其实不是官方支持的产品,学到后来,因为PyQt没有好用的IDE(所以一直用Gvim代替着,Eric怎么看都不习惯,一堆按钮没有章法),而且没有合适的教程参考学习(大部分都是qt3时代的东西),最重要的是个人还是比较喜欢看纸质书籍,而国内很难看到PyQt书籍的出版了。。。。。。。。所以,其实PyQt在学习了一段时间其实慢慢的慢下来了,再加上那时候预知了OPhone将横空出世,将较大的经历转移到了JAVAAndroid的学习中去了。。。。可怜的Python啊。。。。呵呵,连一款完整的GUI都还没有学会-_-!Qt的网址目前是http://qt.nokia.com/。目前个人计划是考虑先学好Qt的根本,C++Qt吧,将来想做界面的时候用PyQt应该也快,毕竟接口还是一样的。因为在家,没有好用的Eclipse C++环境(在家用WindowsWindowsC++还是较为习惯VS,而装着Ubuntu + Eclipse + g++ + qt eclipse插件的笔记本在公司),暂时用qt creator来代替吧,虽然个人觉得qt creator还是太过于功能简单的IDE。。。。

 

三、   Qt的文字显示

Qt原始的设计是用于手工编码产生GUI的,所以简单的程序编码也比较简单,(不像Win32MFC,再简单的程序也是一大堆废物代码),一个简单的文字显示示例如下:(用qt creator的一个很大问题是没有语法高亮,所以我不得不将代码先拷贝到VS中然后再拷贝过来以达到语法高亮的效果)

// main.cpp(程序主程序)

#include <QtGui/QApplication>

#include "fontwidget.h"

 

int main(int argc, char *argv[])

{

   QApplication a(argc, argv);

   FontWidget w;

   w.show();

   return a.exec();

}

 

Fontwidget.h:

#ifndef FONTWIDGET_H

#define FONTWIDGET_H

 

#include <QtGui/QWidget>

 

namespace Ui

{

   class FontWidget;

}

 

class FontWidget : public QWidget

{

   Q_OBJECT

 

public:

   FontWidget(QWidget *parent = 0);

   ~FontWidget();

 

protected:

   void FontWidget::paintEvent(QPaintEvent *event);

 

private:

   Ui::FontWidget *ui;

};

 

#endif // FONTWIDGET_H

 

FontWidget.cpp:

#include "fontwidget.h"

#include "ui_fontwidget.h"

#include <QPainter>

#include <QObject>

FontWidget::FontWidget(QWidget *parent)

: QWidget(parent), ui(new Ui::FontWidget)

{

   ui->setupUi(this);

}

 

FontWidget::~FontWidget()

{

   delete ui;

}

 

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   QString text = tr("Hello World");

   painter.drawText(10,10, text);

}

 

说是简单,其实为了展示一个较为完成的自定义WidgetQt程序,还是牵扯了较多的额外代码,其实真正有意义的仅仅只有  QPainter painter(this);

   QString text = tr("Hello World");

   painter.drawText(10,10, text);

3句而已,这里,说明一下paintEvent,在QtEventsignal特别重要,可以理解为两套不同的消息机制,Event主要用于控件的底层,不直接受你控制,而signal的使用范围不限,并且你可以无限的扩展。Event这种不直接受控制的特性也是非常有用的,因为给出了一套较为容易理解的程序执行流程和规范,基本上,这里EventWin32MFC)中的消息较为类似,paintEvent类似Win32中的WM_DRAW消息的响应(在MFC中就是OnDraw),使用方法上与MFC也较为类似,即通过继承来改变。

需要特别注意的是,QPainterdrawTextWindowsDrawText设计思想上不太一样,这里的Y坐标指的是字符的Baseline位置(基线)。

这点我刚开始不太习惯,(因为很简单的原因),而QPainter的用rect为参数的drawText版本仍然与一般的drawText很类似,比如下面这样:

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   QString text = tr("Hello World");

   painter.drawText(QRect(0,0, 100, 20), text);

}

那么,此处的rect的左上角就代表了文字的左上角,所以个人感觉这里有点比较奇怪。更奇怪的是,不仅仅是这一个借口,drawText的接口只要是用x,y直接来表示位置的时候就是指文字的baseline,用QRect的时候就是top。。。。。。。。。。

总而言之,基本的文字显示方法在Qt中就很明显了,QPainter对象的drawText,需要注意y坐标的意思。。。。。。。。。。

 

四、   字体

其实字体是个更加复杂的问题。。。。有多少人知道在字体的现实问题上MS,Apple,Adobe的研究人员投入了多少精力啊。。。。今天的TrueType可不是一开始就存在的。。。。去简单图形编程的学习(1---文字 (Windows GDI实现)看看window版本中的字体结构有多少参数吧。。。。。。。要是人工去记就像记圆周率一样,相对来说,因为Qt引入了QFont这样较为面向对象的方式,简单了很多.

Qt中对字体也给与了重要支持(其实对于很多人来说PC就是一个文字处理的机器,所以字体相当重要,想想MS最赚钱的软件吧。。Office),

仅仅关于字体就有很多类:(链接直接指向nokiaclass reference

QFontQFontComboBox, QFontDatabase, QFontDialog, QFontEngineInfo, QFontEnginePlugin, QFontInfo

这里,我仅仅想改变QPainterdrawText的字体,所以仅仅使用QFont

另外,QPen可以用于改变drawText的颜色,而这些都是QPainter的属性,通过setXXX来设置。

示例如下:

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   QFont font("Times",50);

   QString text = tr("Hello World");

   painter.setPen(Qt::blue);

   painter.setFont(font);

   painter.drawText(QRect(0,0, 1000, 100), text);

}

效果如插图1.这里是第一次展示Qt的截图,顺便说明一下,QtWindow下并不是使用Windows的原生控件,而是通过Qt控件模拟而成。不要怀疑Qt有原生的控件啊,这也是我学习Qt的原因之一,Qt可是有它的原生平台KDE的(也是Qt的杀手级应用),因为学习Qt我甚至将以前用了好些年的Gnome经验和体验都放弃了,开始适应并改用KDE,ubuntuKDE版本还有特定的名字Kubuntu。。。。。。。。没有办法使用compiz还让我郁闷了好一阵子,因此还查看了一些KDE,Gnome的相关资料,KDEGnome之间的竞争估计也算是IT世界著名而漫长的战争之一了吧(类似的例子还有vim-emacs)。可怜的KDE盛极一时,因为Qt而慢慢被众多公司所抛弃,但是竟然因为Qt是某家公司的产品(虽然开源)而被冷落。。。可见开源世界的人们对自由的极高标准。。。。

 

五、   旋转的字体

按照来自Charles Petzold的创意,见简单图形编程的学习(1---文字 (Windows GDI实现)中的例子,自然我也想要在Qt中实现旋转的字体,并且,这一次不会再有抄袭Charles Petzold的嫌疑了lol,呵呵,虽然还是抄袭了创意,对比Windows中的例子,你会很惊讶的发现Qt的实现实在太简单了,简单的可怕。

 

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   QFont font("Times",50);

   QString text = tr("   Rotation");

   painter.setFont(font);

   int x = (width() / 2);

   int y = (height() / 2);

   painter.setViewport(x, y, width(), height());

 

   for(int i = 0; i < 12; ++i)

   {

      painter.rotate(30);

      painter.drawText(0, 0, text);

   }

}

QPainter::setViewport调整后Viewport后,painter有现成的函数rotate使用,看看实现效果:)见插图2

 

还是老样子,让它旋转起来,这里我还是用两种方式,一种是定时器,一种是手动接管事件循环的方式(Windows的实现是在消息循环外接管消息循环)。

 

1.      用定时器的版本:

Fontwidget.h:

#ifndef FONTWIDGET_H

#define FONTWIDGET_H

 

#include <QtGui/QWidget>

#include <QPainter>

#include <QObject>

 

namespace Ui

{

   class FontWidget;

}

 

class FontWidget : public QWidget

{

   Q_OBJECT

 

public:

   FontWidget(QWidget *parent = 0);

   ~FontWidget();

 

protected:

   void paintEvent(QPaintEvent *event);

   void showEvent(QShowEvent* event);

   void timerEvent(QTimerEvent *event);

 

private:

   Ui::FontWidget *ui;

   int myTimerID;

   unsigned int miOritation;

   QFont *pFont;

   QString *pText;

};

 

#endif // FONTWIDGET_H

 

 

Fontwidget.cpp:

#include "fontwidget.h"

#include "ui_fontwidget.h"

 

FontWidget::FontWidget(QWidget *parent)

: QWidget(parent), ui(new Ui::FontWidget)

{

   ui->setupUi(this);

   miOritation = 0;

   pFont = new QFont("Times",50);

   pText = new QString(tr("   Rotation"));

 

}

 

FontWidget::~FontWidget()

{

   delete ui;

}

 

void FontWidget::showEvent(QShowEvent* event)

{

   myTimerID = startTimer(33);

}

 

void FontWidget::timerEvent(QTimerEvent *event)

{

   if(event->timerId() == myTimerID)

   {

      miOritation += 1;

      repaint();

   }

 

}

 

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   int x = (width() / 2);

   int y = (height() / 2);

   painter.setViewport(x, y, width(), height());

 

   painter.setFont(*pFont);

 

   for(int i = 0; i < 12; ++i)

   {

      painter.rotate(30+miOritation);

      painter.drawText(0, 0, *pText);

   }

}

 

按照正常的思路就是这样做了,但是会发现严重的问题(虽然效果也很有意思),那就是一个循环内多次的rotate后的文字竟然速度不一样,实现了奇怪的后面文字追前面文字的效果。。。。。。。。如插图3所示。呵呵,还好有宝典在手。。。。。C++ GUI Qt4编程》第二版第八章中有类似的描述:“for循环中的代码有一个小缺陷,如果执行了更多的迭代,这一问题会变得很明显。每次调用rotate(),就高效地用一个旋转矩阵去乘当前的世界变换,从而创建一个新的世界变换。浮点数的舍入误差不断的累积,得到了越来越不准确的世界变换。”就是这个原因,才有了我们这样的效果。我们这里比原书中的例子rotate了更多次,因为这里是动画(每秒30帧左右),原书是静态画面。原书的解决方案是使用QPaintersave(),restore()函数为每次迭代保存和加载原始的矩阵。

正确的做法是:

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   int x = (width() / 2);

   int y = (height() / 2);

   painter.setViewport(x, y, width(), height());

 

   painter.setFont(*pFont);

 

   for(int i = 0; i < 12; ++i)

   {

      int liOritation = 30 * i + miOritation;

      painter.save();

      painter.rotate(liOritation);

      painter.drawText(0, 0, *pText);

      painter.restore();

   }

}

这样的效果就正常了,而且正常的惊人,因为我们没有为图形的显示进行任何优化以防止闪烁,(简单图形编程的学习(1---文字 (Windows GDI实现)》中类似的例子闪烁的就非常明显)在《C++ GUI Qt4编程》中说明了Qt4竟然会自动为我们对图形的现实进行双缓冲处理-_-!呵呵,甚至不用我们通过编程手动指定就能实现这样的效果,这也算是Qt框架设计之人性化的又一个体现吧,我很享受这样的人性化^^

 

2.      手动接管事件循环的版本:

这个版本就类似于《简单图形编程的学习(1---文字 (Windows GDI实现)》中使用PeekMessage的版本了,以后要想用Qt做游戏并达到很好的动画效果估计也就靠这种方式来实现了。

Main:

#include <QtGui/QApplication>

#include "fontwidget.h"

#include <QtTest/QTest>

#include <QTime>

 

 

int main(int argc, char *argv[])

{

   QApplication a(argc, argv);

   FontWidget w;

   w.show();

   QTime timer;

   while(true)

   {

      timer.start();

      a.processEvents();

      w.addOritation();

      w.repaint();

 

      while(timer.elapsed() < 33)

      {

        QTest::qSleep(1);

      }

   }

}

 

fontwidget.h

#ifndef FONTWIDGET_H

#define FONTWIDGET_H

 

#include <QtGui/QWidget>

#include <QPainter>

#include <QObject>

 

namespace Ui

{

   class FontWidget;

}

 

class FontWidget : public QWidget

{

   Q_OBJECT

 

public:

   FontWidget(QWidget *parent = 0);

   ~FontWidget();

 

   void addOritation() { miOritation++; }

 

protected:

   void paintEvent(QPaintEvent *event);

   void keyPressEvent(QKeyEvent *event);

   void closeEvent(QCloseEvent *event);

private:

   Ui::FontWidget *ui;

   int myTimerID;

   unsigned int miOritation;

   QFont *pFont;

   QString *pText;

};

 

#endif // FONTWIDGET_H

 

fontwidget.cpp:

#include "fontwidget.h"

#include "ui_fontwidget.h"

#include <QtGui>

 

FontWidget::FontWidget(QWidget *parent)

: QWidget(parent), ui(new Ui::FontWidget)

{

   ui->setupUi(this);

   miOritation = 0;

   pFont = new QFont("Times",50);

   pText = new QString(tr("   Rotation"));

 

}

 

FontWidget::~FontWidget()

{

   delete ui;

}

 

void FontWidget::keyPressEvent(QKeyEvent *event)

{

   // 响应Esc键以退出程序

   if(event->key() == Qt::Key_Escape)

   {

      exit(0);

   }

}

 

void FontWidget::closeEvent(QCloseEvent *event)

{

   exit(0);

}

 

void FontWidget::paintEvent(QPaintEvent *event)

{

   QPainter painter(this);

   int x = (width() / 2);

   int y = (height() / 2);

   painter.setViewport(x, y, width(), height());

 

   painter.setFont(*pFont);

 

   for(int i = 0; i < 12; ++i)

   {

      int liOritation = 30 * i + miOritation;

      painter.save();

      painter.rotate(liOritation);

      painter.drawText(0, 0, *pText);

      painter.restore();

   }

}

 

效果非常好:)相对来说会比定时的版本动画平稳很多,并且,Qt还是让这样的动画没有任何闪烁,学习过的GUI不算不可计数,但是真正让人感觉很愉快的是在仅仅发现Qt一种,控制能力还是很强大,灵活,并且很为程序员着想,不愧是以前专门卖框架的公司开发的。。。。

 

六、   参考:

1. C++ GUI Qt4编程》第二版(原版名《C++ GUI Programming with Qt4,Second Edition》,Jasmin Blanchette,Mark Summerfield著,电子工业出版社

 

 

插图

插图1:

插图2:

插图3:

 

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com



阅读全文....

变“从U盘/硬盘安装Linux ”的痛苦为享受的工具,UNetbootin

遥想当年,因为没有刻录机,所以尝试过从硬盘安装ubuntu。。。。那也算是个痛苦的经历,google了好几篇无效的文章,导致焦头烂额,启动文件不匹配,找不到地方下载,grup,grupfordos等等东西都用尽了,最后才成功安装,但是今天再次尝试从U盘安装ubuntu的时候,轻松了就不止一星半点了,因为有了UNetbootin,实在佩服很多人的才智,我感觉到一个事情麻烦的时候,去抱怨,人家呢?将其变得简单。。。。。。。。。。。。。佩服,特别在Linux的时候,开源的世界,配合网络,几乎无所不能。。。。。新立得,apt等就是最佳例证,当年redhat9时代,rpmfind网站没有少去,血没有少吐,现在已经进入享受的时代了。。。。。。。。。。。

 

UNetbootin的使用方法就不多说了,那是怀疑大家的智商,还是感谢UNetbootin的制作者,因为他们,世界更加精彩。

 

UNetbootin的主页是:http://unetbootin.sourceforge.net

 

支持的Linux列表之长更加让人感叹:

 

 

 

再感谢sourceforge给了我们一个这样好的平台。。。。。怎么好像去领奖似的-_-!呵呵,让我们从郁闷中恢复过来,开始享受生活。

阅读全文....

Qt Creator的库依赖问题

Qt Creator的Qt库中途添加依赖的问题

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

 

这里说一下,Qt Creator实在不是个什么好产品,在创建工程的时候可以用GUI选择你需要依赖的Qt模块,这样你可以仅仅通过包含头文件名即可正确包含头文件,但是没有选择的话,你需要包含相对目录,比如假如我开始选择了依赖QtTest模块,我仅仅需要

#include <QTest>即可

不过我开始没有选择QtTest(没有想到sleep在这里面),这个时候我必须

#include <QtTest/QTest>

最奇怪的是,我没有办法制定工程添加QtTest的库依赖。。。。。。导致连接总是无法成功,(ld报错),搞了一会都没有发现Creator中有哪个地方可以添加(希望有高人可以指点),pro工程中也没有任何相关的地方可以编辑,最后没有办法,在工程目录下的makefile中自己手动添加了(要是没有在Unix/Linux下搞过开发,学过Makefile+gcc的人估计要吐血了)。另外,也理解了为啥没有包含模块就必须要添加相对路径了,MakefileIncludes中没有指定相应的目录。指定后就完全等同于开始就选择了库依赖了。

 

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

阅读全文....

简单图形编程的学习(2)---点 (Windows GDI实现)


简单图形编程的学习(2--- (Windows GDI实现)

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

一、   又一顿牢骚

虽然知道不应该老是说些与技术无关的话。。。。但是有的时候又总是想说。。。。难怪有同事说我最近已经有点像唐僧了-_-!总而言之,因为相对来说书看的太快,(现在租的房子离公司太远,老是坐地铁,导致有了非常固定的看书时间),而因为工作一直太忙,一直加班回家太晚的原因,所以实际的实践太慢(基本上现在就是以写博客的形式),所以QtAndroid的部分要是同步跟上我DirectX的书都要看好几本了,这样的方式好像不太好,所以目前暂时还是以Windows的为主了。。。。这也体现了一点理想与现实的差距-_-!虽然初期项目目标过大,项目中即时调整起码还能保证项目完成吧。。。。。(扯的远了)。

 

二、   画点

很简单的一个Windows GDI函数,SetPixel,原型如下:

COLORREF SetPixel(
  HDC hdc,           // handle to DC
  int X,             // x-coordinate of pixel
  int Y,             // y-coordinate of pixel
  COLORREF crColor   // pixel color
);

 

也许属于最最简单的Windows GDI 之一了,但是如同在Small Basic画点中所讲解的一样,画点这样简单的函数可以实现无限的效果。还是那句话,能够设置一个像素点,就能够描绘一个世界。。。。。。唯一限制程序实现的就是编写程序人的思维。

因为Windows代码本身的复杂性,不能如Small Basic那样直击要害,要是每次给出完整代码太占用空间,这里给出《Tricks Of the Windows Game Programming GURUS》一书中的框架代码,方便以后代码的添加。

// T3D Game Console, creates a game console application

 

// INCLUDES ///////////////////////////////////////////////

#define WIN32_LEAN_AND_MEAN  // just say no to MFC

 

#include <tchar.h>

#include <windows.h>   // include important windows stuff

#include <windowsx.h>

#include <mmsystem.h>

#include <iostream> // include important C/C++ stuff

#include <conio.h>

#include <stdlib.h>

#include <malloc.h>

#include <memory.h>

#include <string.h>

#include <stdarg.h>

#include <stdio.h>

#include <math.h>

#include <io.h>

#include <fcntl.h>

 

// DEFINES ////////////////////////////////////////////////

 

// defines for windows

#define WINDOW_CLASS_NAME _T("WINCLASS1")

 

// MACROS /////////////////////////////////////////////////

 

#define KEYDOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

#define KEYUP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

 

// GLOBALS ////////////////////////////////////////////////

HWND      main_window_handle = NULL; // globally track main window

HINSTANCE hinstance_app      = NULL; // globally track hinstance

 

char buffer[80];                     // general printing buffer

 

#define FRAME_PER_SECOND (20)

#define TIME_IN_FRAME (1000/FRAME_PER_SECOND)

#define WIDTH 800

#define HEIGHT 600

 

 

// FUNCTIONS //////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hwnd,

                    UINT msg,

                    WPARAM wparam,

                    LPARAM lparam)

{

   // this is the main message handler of the system

   PAINTSTRUCT   ps;     // used in WM_PAINT

   HDC           hdc;  // handle to a device context

   char buffer[80] = {0};        // used to print strings

 

   // what is the message

   switch(msg)

   { 

   case WM_CREATE:

      {

        // do initialization stuff here

        // return success

        return(0);

      } break;

 

   case WM_PAINT:

      {

        // simply validate the window

        hdc = BeginPaint(hwnd,&ps);

 

        // end painting

        EndPaint(hwnd,&ps);

 

        // return success

        return(0);

      } break;

 

   case WM_DESTROY:

      {

 

        // kill the application, this sends a WM_QUIT message

        PostQuitMessage(0);

 

        // return success

        return(0);

      } break;

 

   default:break;

 

   } // end switch

 

   // process any messages that we didn't take care of

   return (DefWindowProc(hwnd, msg, wparam, lparam));

 

} // end WinProc

 

///////////////////////////////////////////////////////////

 

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

   while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   {

      Sleep(1);

   }

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

////////////////////////////////////////////////////////////

 

int Game_Init(void *parms = NULL, int num_parms = 0)

{

   // this is called once after the initial window is created and

   // before the main event loop is entered, do all your initialization

   // here

 

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Init

 

/////////////////////////////////////////////////////////////

 

int Game_Shutdown(void *parms = NULL, int num_parms = 0)

{

   // this is called after the game is exited and the main event

   // loop while is exited, do all you cleanup and shutdown here

 

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Shutdown

 

// WINMAIN ////////////////////////////////////////////////

int WINAPI WinMain( HINSTANCE hinstance,

              HINSTANCE hprevinstance,

              LPSTR lpcmdline,

              int ncmdshow)

{

 

   WNDCLASSEX winclass; // this will hold the class we create

   HWND     hwnd; // generic window handle

   MSG        msg;    // generic message

   HDC        hdc;      // graphics device context

 

   // first fill in the window class stucture

   winclass.cbSize         = sizeof(WNDCLASSEX);

   winclass.style        = CS_DBLCLKS | CS_OWNDC |

      CS_HREDRAW | CS_VREDRAW;

   winclass.lpfnWndProc  = WindowProc;

   winclass.cbClsExtra   = 0;

   winclass.cbWndExtra   = 0;

   winclass.hInstance    = hinstance;

   winclass.hIcon        = LoadIcon(NULL, IDI_APPLICATION);

   winclass.hCursor    = LoadCursor(NULL, IDC_ARROW);

   winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

   winclass.lpszMenuName = NULL;

   winclass.lpszClassName = WINDOW_CLASS_NAME;

   winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

 

   // save hinstance in global

   hinstance_app = hinstance;

 

   // register the window class

   if (!RegisterClassEx(&winclass))

      return(0);

 

   // create the window

   if (!(hwnd = CreateWindowEx(NULL,                  // extended style

      WINDOW_CLASS_NAME,     // class

      _T("Show Point 0.1"), // title

      WS_OVERLAPPEDWINDOW | WS_VISIBLE,

      0,0,    // initial x,y

      WIDTH,HEIGHT,  // initial width, height

      NULL,   // handle to parent

      NULL,   // handle to menu

      hinstance,// instance of this application

      NULL))) // extra creation parms

      return(0);

 

   // save main window handle

   main_window_handle = hwnd;

 

   // initialize game here

   Game_Init();

 

   // enter main event loop

   while(TRUE)

   {

      // test if there is a message in queue, if so get it

      if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

      {

        // test if this is a quit

        if (msg.message == WM_QUIT)

           break;

 

        // translate any accelerator keys

        TranslateMessage(&msg);

 

        // send the message to the window proc

        DispatchMessage(&msg);

      } // end if

 

      // main game processing goes here

      Game_Main();

 

   } // end while

 

   // closedown game here

   Game_Shutdown();

 

   // return to Windows like this

   return(msg.wParam);

 

} // end WinMain

 

///////////////////////////////////////////////////////////

 

 

 

1.      随机在屏幕上画随机颜色点

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

   HDC hdc;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

  

   hdc = GetDC(main_window_handle);

 

   // draw 1000 pixels

   for (int index=0; index < 1000; index++)

   {

      // get random position

      int x = rand()%WIDTH;

      int y = rand()%HEIGHT;

 

      COLORREF color = RGB(rand()%255,rand()%255,rand()%255);

      SetPixel(hdc, x,y, color);

 

   } // end for index

 

   // release the dc

   ReleaseDC(main_window_handle, hdc);

 

   while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   {

      Sleep(1);

   }

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

同样还是简单,当然,前提是框架存在并且熟悉了一大堆Windows的特性以后,说实话,Windows的死消息机制也不是一天两天就熟悉的了的,我当年学MFC的时候那是一愣一愣的,用了较旧以后才能大概知道怎么回事儿。知道这些以后,剩下的也就是一个Rand函数+SetPixel函数的理解量了。这里不放截图了,这么简单的东西放个截图我都觉得没有意思。

 

2.      老电视机雪花点的效果:

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

   HDC hdc;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

  

   hdc = GetDC(main_window_handle);

 

   // draw 1000 pixels

   for (int index=0; index < 500; index++)

   {

      // get random position

      int x = rand()%WIDTH;

      int y = rand()%HEIGHT;

 

      COLORREF color = RGB(255,255,255);

      SetPixel(hdc, x,y, color);

 

   } // end for index

 

   // release the dc

   ReleaseDC(main_window_handle, hdc);

 

   Sleep(10);

   InvalidateRect(main_window_handle, NULL, TRUE);

   //while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   //{

   // Sleep(1);

   //}

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

这样基本能够达到效果,但是实际上还有点问题,为了统一程序的架构方便讲解才这样写代码,这里因为利用Windows原有消息去擦除原有点,放在WM_DRAW中去做画点效果会更好一点。

 

3.      闪烁的星空:

#define POSITION_COUNT (500)

int gaWidth[POSITION_COUNT];

int gaHeight[POSITION_COUNT];

 

///////////////////////////////////////////////////////////

 

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

   HDC hdc;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

  

   hdc = GetDC(main_window_handle);

   for (int index=0; index < POSITION_COUNT; index++)

   {

      SetPixel(hdc, gaWidth[index], gaHeight[index], RGB(255,255,255));

      gaWidth[index] += 1;

      gaHeight[index] += 1;

   } // end for index

 

   Sleep(1000);

 

 

   Sleep(10);

   // release the dc

   ReleaseDC(main_window_handle, hdc);

   //while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   //{

   // Sleep(1);

   //}

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

////////////////////////////////////////////////////////////

 

int Game_Init(void *parms = NULL, int num_parms = 0)

{

   // this is called once after the initial window is created and

   // before the main event loop is entered, do all your initialization

   // here

 

   // 一次初始化一个随机POSITION_COUNT大小的数组用于固定位置

   for (int index=0; index < POSITION_COUNT; index++)

   {

      // get random position

      gaWidth[index] = rand()%WIDTH;

      gaHeight[index] = rand()%HEIGHT;

 

   } // end for index

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Init

 

Small Basic实现的方式我发现闪烁效果没有Small Basic好,原因可能是CWin32程序速度比Small Basic快太多了,以至于几乎看不到闪烁,于是,按上面这样将闪烁实际的用Sleep停留一下才能看到较好的效果。也算是不同语言实现同一个算法(大概这么称呼实现这个效果的方法吧)需要注意的不同之处。

 

 

4.      屏幕刮花效果

///////////////////////////////////////////////////////////

 

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

   HDC hdc;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

  

   hdc = GetDC(main_window_handle);

   for (int index=0; index < POSITION_COUNT; index++)

   {

      SetPixel(hdc, gaWidth[index], gaHeight[index], RGB(255,255,255));

 

      // 这算是实现的一种,横向刮花

      gaWidth[index] += 1;

 

      // 这算是实现的另一种,斜向刮花

      //gaWidth[index] += 1;

      //gaHeight[index] += 1;

 

      // 这算是实现的又一种,纵向刮花,纵向刮花建议配合血红色颜色观看效果。。。。。。

      //gaHeight[index] += 1;

 

   } // end for index

 

   // release the dc

   ReleaseDC(main_window_handle, hdc);

   while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   {

      Sleep(1);

   }

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

////////////////////////////////////////////////////////////

 

int Game_Init(void *parms = NULL, int num_parms = 0)

{

   // this is called once after the initial window is created and

   // before the main event loop is entered, do all your initialization

   // here

 

   // 一次初始化一个随机POSITION_COUNT大小的数组用于固定位置

   for (int index=0; index < POSITION_COUNT; index++)

   {

      // get random position

      gaWidth[index] = rand()%WIDTH;

      gaHeight[index] = rand()%HEIGHT;

 

   } // end for index

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Init

 

一个屏幕刮花效果,不同的方向给人感受完全不同,最有意思的是纵向向下的红色效果,如插图1.让我想起某游戏死亡时的结束画面,满眼都是向下流动的血液。。。。。。。。

 

5.      移动的星空:

本来用我在Small Basic中的方法实现也可以出现移动的星空的,但是我发现《Tricks of the Windows Game Programming GURUS》一书中的例子更加有趣,这里引用一下了。

///////////////////////////////////////////////////////////

 

void Init_Stars(void)

{

// this function initializes all the stars

 

for (int index=0; index < NUM_STARS; index++)

    {

    // select random position

    stars[index].x = rand()%WINDOW_WIDTH;

    stars[index].y = rand()%WINDOW_HEIGHT;

 

    // set random velocity  

    stars[index].vel = 1 + rand()%16;

 

    // set intensity which is inversely prop to velocity for 3D effect

    // note, I am mixing equal amounts of RGB to make black -> bright white   

    int intensity = 15*(17 - stars[index].vel);

    stars[index].col = RGB(intensity, intensity, intensity);

 

    } // end for index

 

} // end Init_Stars

 

////////////////////////////////////////////////////////////

 

void Erase_Stars(void)

{

// this function erases all the stars

for (int index=0; index < NUM_STARS; index++)

    SetPixel(global_dc, stars[index].x, stars[index].y, RGB(0,0,0));

 

} // end Erase_Stars

 

////////////////////////////////////////////////////////////

 

void Draw_Stars()

{

// this function draws all the stars

for (int index=0; index < NUM_STARS; index++)

    SetPixel(global_dc, stars[index].x, stars[index].y, stars[index].col);

 

 

} // end Draw_Stars

 

////////////////////////////////////////////////////////////

 

void Move_Stars(void)

{

// this function moves all the stars and wraps them around the

// screen boundaries

for (int index=0; index < NUM_STARS; index++)

    {

    // move the star and test for edge

    stars[index].x+=stars[index].vel;

 

    if (stars[index].x >= WINDOW_WIDTH)

        stars[index].x -= WINDOW_WIDTH;

   

    } // end for index

 

} // end Move_Stars

 

////////////////////////////////////////////////////////////

 

int Game_Main(void *parms = NULL, int num_parms = 0)

{

// this is the main loop of the game, do all your processing

// here

 

// get the time

DWORD start_time = GetTickCount();

 

// erase the stars

Erase_Stars();

 

// move the stars

Move_Stars();

 

// draw the stars

Draw_Stars();

 

// lock to 30 fps

while((start_time - GetTickCount() < 33));

 

// for now test if user is hitting ESC and send WM_CLOSE

if (KEYDOWN(VK_ESCAPE))

   SendMessage(main_window_handle,WM_CLOSE,0,0);

 

// return success or failure or your own return code here

return(1);

 

} // end Game_Main

 

////////////////////////////////////////////////////////////

 

int Game_Init(void *parms = NULL, int num_parms = 0)

{

// this is called once after the initial window is created and

// before the main event loop is entered, do all your initialization

// here

 

// first get the dc to the window

global_dc = GetDC(main_window_handle);

 

// initialize the star field here

Init_Stars();

 

// return success or failure or your own return code here

return(1);

 

} // end Game_Init

 

/////////////////////////////////////////////////////////////

 

int Game_Shutdown(void *parms = NULL, int num_parms = 0)

{

// this is called after the game is exited and the main event

// loop while is exited, do all you cleanup and shutdown here

 

// release the global dc

ReleaseDC(main_window_handle, global_dc);

 

// return success or failure or your own return code here

return(1);

 

} // end Game_Shutdown

 

书中例子利用不同的亮度,及不同的移动速度来模拟一种类3D的效果。。。。。。。。。。。。估计不是一般的人能想到的,呵呵,要知道,仅仅利用了一个SetPixel函数。。。。。。。

 

Have Funaha?在有了一个大概的思路以后,其实Window下面的GDI编程也没有那么难吧,的确是没有那么难吧?毕竟我们专注的也就一个SetPixel函数而已了 ,越专注反而能让我们有更多新的想法。

这里用Windows GDI来实现我从Small Basic学到的一招显示文字的华丽技巧,你以前要是从来没有看过类似例子(也不是个在图形编程领域混过很多年的骨灰级程序员)你别说看了没有感觉惊艳,要知道其实仅仅是利用了画点和文字输出两个如此平常而简单的特性。

6.      星空中的文字

///////////////////////////////////////////////////////////

 

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

  

   for (int index=0; index < 1000; index++)

   {

      // get random position

      int x = rand()%WIDTH;

      int y = rand()%HEIGHT;

 

      COLORREF color = RGB(rand()%255,rand()%255,rand()%255);

      SetPixel(ghDC, x,y, color);

 

   } // end for index

 

   TextOut(ghDC, 100, 100, CHAR_OUT, _tcslen(CHAR_OUT));

 

   // release the dc

   while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   {

      Sleep(1);

   }

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

////////////////////////////////////////////////////////////

 

int Game_Init(void *parms = NULL, int num_parms = 0)

{

   // this is called once after the initial window is created and

   // before the main event loop is entered, do all your initialization

   // here

   HFONT hfont;

 

   ghDC = GetDC(main_window_handle);

 

   hfont = CreateFont( 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("新宋体"));

 

   SelectObject(ghDC, hfont);

 

   SetTextColor(ghDC, RGB(0,0,0));

   SetBkColor(ghDC, RGB(0,0,0));

 

   DeleteObject(hfont);

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Init

 

/////////////////////////////////////////////////////////////

 

int Game_Shutdown(void *parms = NULL, int num_parms = 0)

{

   // this is called after the game is exited and the main event

   // loop while is exited, do all you cleanup and shutdown here

 

   ReleaseDC(main_window_handle, ghDC);

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Shutdown

按照以前的实现思想,我很快写出了上述程序,结果效果和我想象的不太一样,反而有点像个面具。。。。。留出了眼睛的观察窗口。。。-_-!见插图2。实际的原因想了一下才知道,背景前景都是黑的,当时的第一想法是不能让星空给盖了,但是这样不都黑了啊?。。。。呵呵,改成下面这个样子,效果就出来了,多的行用红色标明,看了就明白了,让背景透明,能够被星空给盖了,这样才能显示出文字。

///////////////////////////////////////////////////////////

 

int Game_Main(void *parms = NULL, int num_parms = 0)

{

   DWORD dwStartTime;

 

   dwStartTime = GetTickCount();

   // this is the main loop of the game, do all your processing

   // here

 

   // for now test if user is hitting ESC and send WM_CLOSE

   if (KEYDOWN(VK_ESCAPE))

      SendMessage(main_window_handle,WM_CLOSE,0,0);

 

  

   for (int index=0; index < 300; index++)

   {

      // get random position

      int x = rand()%WIDTH;

      int y = rand()%HEIGHT;

 

      COLORREF color = RGB(rand()%255,rand()%255,rand()%255);

      SetPixel(ghDC, x,y, color);

 

   } // end for index

 

   TextOut(ghDC, 100, 100, CHAR_OUT, _tcslen(CHAR_OUT));

 

   // release the dc

   while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   {

      Sleep(1);

   }

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Main

 

////////////////////////////////////////////////////////////

 

int Game_Init(void *parms = NULL, int num_parms = 0)

{

   // this is called once after the initial window is created and

   // before the main event loop is entered, do all your initialization

   // here

   HFONT hfont;

 

   ghDC = GetDC(main_window_handle);

 

   hfont = CreateFont( 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("新宋体"));

 

   SelectObject(ghDC, hfont);

 

   SetTextColor(ghDC, RGB(0,0,0));

   SetBkMode (ghDC, TRANSPARENT);

 

   DeleteObject(hfont);

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Init

 

/////////////////////////////////////////////////////////////

 

int Game_Shutdown(void *parms = NULL, int num_parms = 0)

{

   // this is called after the game is exited and the main event

   // loop while is exited, do all you cleanup and shutdown here

 

   ReleaseDC(main_window_handle, ghDC);

 

 

   // return success or failure or your own return code here

   return(1);

 

} // end Game_Shutdown

 

我第一次看到这个例子的时候真的感叹作者是个天才-_-!也许是自己太笨了所以想不到用这样的方式去显示文字吧。这次来个系列效果,可以参考《简单图形编程的学习(2--- (small basic实现)》文中的插图效果,或者简单的自己运行一下就好了。

 

三、   小结

一个个简单的点就能够构成如此繁多的效果,简直有点不可思议,但是其实,能够绘制一个点,就能够绘制整个世界,要知道,整个屏幕不过也就是一个一个像素构成的,呵呵。其实,从另外的角度来说,一连串连续的点就能构成一条直线,一排排直线就能构成一个面,有了点,线,面,还有什么不够构成的?你可以表达整个世界。另外,就我看的老的游戏编程书籍介绍,DirectDraw的原始接口也仅仅是能画点/位图而已,游戏的开发的先驱们还不是用这样简单的接口实现了那么多画面丰富,效果华丽的2D游戏啊?

 

插图

插图一:

插图2:

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

阅读全文....

简单图形编程的学习(2)---点 (small basic实现)


简单图形编程的学习(2--- (small basic实现)

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

一、   又一顿牢骚

虽然知道不应该老是说些与技术无关的话。。。。但是有的时候又总是想说。。。。难怪有同事说我最近已经有点像唐僧了-_-!总而言之,因为相对来说书看的太快,(现在租的房子离公司太远,老是坐地铁,导致有了非常固定的看书时间),而因为工作一直太忙,一直加班回家太晚的原因,所以实际的实践太慢(基本上现在就是以写博客的形式),所以QtAndroid的部分要是同步跟上我DirectX的书都要看好几本了,这样的方式好像不太好,所以目前暂时还是以Windows的为主了。。。。这也体现了一点理想与现实的差距-_-!虽然初期项目目标过大,项目中即时调整起码还能保证项目完成吧。。。。。(扯的远了)。

 

二、   画点

画点,在Small Basic中属于太基础的东西,当然,其实在Small Basic中什么都基础。。。呵呵

GraphicsWindow.SetPixel

函数用于画点,这里的点仅仅只有一个像素,所以叫SetPixel(设置像素),和Windows GDI的命名一致(其实Small Basic中的画图函数很多都与Windows GDI一致),参数的解释如下:

SetPixel
Draws the pixel specified by the x and y co-ordinates using the specified color. 

GraphicsWindow.
SetPixel(x, y, color)

x
The x co-ordinate of the pixel.
y
The y co-ordinate of the pixel.
color
The color of the pixel to set.
 
Returns
Nothing

1.      随机在屏幕上画随机颜色点(HHT897

GraphicsWindow.BackgroundColor = "White"

GraphicsWindow.PenColor = "LightBlue"

gw = GraphicsWindow.Width

gh = GraphicsWindow.Height

 

While ("True")

  GraphicsWindow.SetPixel(Math.GetRandomNumber(gw), Math.GetRandomNumber(gh), GraphicsWindow.GetRandomColor())

EndWhile

 

So简单。。。不是吗?效果如插图1

但是,不要小看点的作用,点可以用于模拟星空。。。。。。。。。这里展示几个效果,真的觉得small basic用于演示什么叫简单的技术惊艳的效果非常合适。。。。。。在图形领域,感觉技术固然重要,但是思维强大也能利用简单的技术实现惊艳的效果。

2.      老电视机雪花点的效果:(PXB396)

GraphicsWindow.BackgroundColor = "DarkNight"

GraphicsWindow.PenColor = "LightBlue"

gw = GraphicsWindow.Width

gh = GraphicsWindow.Height

 

While ("True")

  For i = 1 To 1000

    GraphicsWindow.SetPixel(Math.GetRandomNumber(gw), Math.GetRandomNumber(gh), "White")

  EndFor

  Program.Delay(10)

  GraphicsWindow.Clear()

EndWhile

 

3.      闪烁的星空:(TPK996)

GraphicsWindow.BackgroundColor = "DarkNight"

GraphicsWindow.PenColor = "LightBlue"

gw = GraphicsWindow.Width

gh = GraphicsWindow.Height

 

' 以数组记录下随机出来的点,这样才能保证星空是在闪烁而不是移动

For i = 1 To 500

  width[i] = Math.GetRandomNumber(gw)

  height[i] = Math.GetRandomNumber(gh)

EndFor

 

While ("True")

  For i = 1 To 500

    GraphicsWindow.SetPixel(width[i], height[i], "White")

  EndFor

  Program.Delay(1000)

  GraphicsWindow.Clear()

EndWhile

 

4.      屏幕刮花效果(RMP025

 

GraphicsWindow.BackgroundColor = "DarkNight"

GraphicsWindow.PenColor = "LightBlue"

gw = GraphicsWindow.Width

gh = GraphicsWindow.Height

 

 

For i = 1 To 500

  width[i] = Math.GetRandomNumber(gw)

  height[i] = Math.GetRandomNumber(gh)

EndFor

 

While ("True")

  For i = 1 To 500

    GraphicsWindow.SetPixel(width[i], height[i], "White")

    width[i] = width[i] + 1

  EndFor

 

  Program.Delay(10)

EndWhile

 

 

5.      移动的星空:(ZGB224

GraphicsWindow.BackgroundColor = "DarkNight"

GraphicsWindow.PenColor = "LightBlue"

gw = GraphicsWindow.Width

gh = GraphicsWindow.Height

 

 

For i = 1 To 50

  width[i] = Math.GetRandomNumber(gw)

  height[i] = Math.GetRandomNumber(gh)

EndFor

 

While ("True")

  Program.Delay(1)

  For i = 1 To 50

    GraphicsWindow.SetPixel(width[i], height[i], "White")

    width[i] = width[i] + 1

   

    ' 保证星空不是直接消失了-_-!

    If(width[i] > gw) Then

      width[i] = 0

    EndIf

  EndFor

 

  GraphicsWindow.Clear()

EndWhile

 

Have Funaha?呵呵,的确是,很久没有这样爽的写程序了,有了思维,很简单的就能体现在Small Basic上,让人愉快。后面的字母都是可以直接在Small Basicimport的,现在Small Basic 0.6出来了,我用的都是Small Basic 0.6。另外,发现没有,不像在讲其他语言/程序的时候一样,对各个参数一通饱讲,10分钟还没有看到一个函数的参数,对于Small Basic的程序我感觉仅仅需要展示效果和源代码就好了,展示的直接就是编程的思想,而不是语言,因为语言本身如此的简单。完成上面所有的示例都没有花掉我一个小时。。。。。很难想象用GDI或者DX我要用多久。。。。。。。呵呵,虽然我用C/C++出身的(现在也靠这个吃饭),也稍微学习过一下汇编,但是我怎么感觉我对越简单的语言越有好感啊?LUA, Python, Bash ,JAVA都稍微学过一点,但是实在是没有如Small Basic这样让人愉快的语言了^^,也许最最重要的一点在于,现有的大部分语言(上面提及的都是),逻辑表达能力虽然很强,库很丰富,但是为了适应足够广阔的领域并达到工业强度,GUI编程方面都是复杂的让人吐血,MFC就不说了,TK号称简单,其实我感觉也好不到哪去,我没有尝试过用Bash没写GUIQt已经算是非常好的GUI库了,但是上百个类足够让你头晕目眩。Small Basic这样的语言虽然是玩具,也就因为其是玩具才敢这么简单。。。。。。。。。呵呵,欣赏它,起码作为一种简单的演示也不错。

 

上面的例子都是自己随便想的,下面看一个偷师来的例子,以前在讲small Basic的时候其实已经展示过了,但是因为这个例子给了我太多惊喜,我决定反复提起,告诉你们什么叫编程思维利用简单的技术,你别说看了没有感觉惊艳,要知道其实仅仅是利用了画点和文字输出两个如此平常而简单的特性。

6.      星空中的文字(HQG707

GraphicsWindow.BackgroundColor = "midnight"

gw = GraphicsWindow.Width

gh = GraphicsWindow.Height

GraphicsWindow.FontSize = 100

Turtle.Move (100)

Turtle.Turn (1*1)

While ("True")

  For i = 1 To 50

   GraphicsWindow.SetPixel(Math.GetRandomNumber(gw),Math.GetRandomNumber(gh),GraphicsWindow.GetRandomColor())

 EndFor

 Turtle.Move(1)

  GraphicsWindow.BrushColor = "Black"

  GraphicsWindow.DrawBoundText(30,110,gw-20,"Small Basic")

 

EndWhile

 

第一次看到这个例子的时候我真的感叹作者是个天才-_-!也许是自己太笨了所以想不到用这样的方式去显示文字吧。这次来个系列效果,如星空中的文字-插图1-4。怎么样?效果惊艳吧?呵呵,直接运行一下程序吧,将文字改成你想要的,你会有更好的感觉。

 

三、   小结

一个个简单的点就能够构成如此繁多的效果,简直有点不可思议,但是其实,能够绘制一个点,就能够绘制整个世界,要知道,整个屏幕不过也就是一个一个像素构成的,呵呵。其实,从另外的角度来说,一连串连续的点就能构成一条直线,一排排直线就能构成一个面,有了点,线,面,还有什么不够构成的?你可以表达整个世界。

 


 

 

 

 

 

 

插图1:

插图2:

 

星空中的文字-插图1:

星空中的文字-插图2:

星空中的文字-插图3:

星空中的文字-插图4:

 

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

阅读全文....

Small Basic V0.6 出来了,快报

Small Basic V0.6 出来了,快报

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

今天在Small Basic的论坛上查看有趣的信息,无意看到

微软官方消息:Small Basic V0.6 is Now Available for Download。。。。。。。

Small Basic 的开发速度明显要快于微软一般的产品,几个一个月前我刚开始看到Small Basic这个有意思的东西的时候还是0.4,现在已经0.6了。。。。。阿门,继续有意思下去吧。。。。。。。。。。继续bring fun back to programming 吧。。。。。。

 

以下是官方博客发表的内容:

 

We have a new version of Small Basic for download at http://smallbasic.comThis release adds German localization on top of existing French, Spanish and Russian.

Also, this release sports a lot of small bug-fixes and some most requested features:

Updated the manual to include a chapter on Arrays 

Added Zoom capabilities to Shape

Added Arc Trigonometric operations in the Math object

Removed Arguments object and moved the functionality into Program object

GetAllIndices operation on Array allows iteration on top of all array values

Added ElapsedMilliseconds to help measure time

Added TextInput events, to help write text input features on GraphicsWindow

Fixed crashes related to event subscription

Fixed cursor visibility issues

When you have downloaded and installed, import STARGATES and try out the fun game.

 

粗略翻译如下:

特性:

1.升级文档以包含数组的章节(数组是在0.5版本新添的内容)

2.加入图形缩放的能力(强大啊)

3.Math对象中加入三角函数操作(方便图形计算)

4.移除Arguments对象,并将相关功能移到Program对象中

5.对数组的GetAllIndices操作允许遍历所有的数组值

6.增加ElapsedMilliseconds以帮助计算时间

7.添加TextInput时间来帮助实现GraphicsWindow的文字输入特性

8.修复event subscription相关的崩溃问题

9.修复鼠标光标的显示问题。

 

最后,导入STARGATES可以尝试玩玩Small Basic编写的一个游戏:)

你不会还不会用Small Basic导入吧:)

 

我不太喜欢MS的大部分东西(包括Windows),但是,我毫不掩饰对Small Basic的喜爱。。。。。

 

STARGATES的游戏截图如下:(游戏还是一般)

StarGate截图

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

 

 

阅读全文....

简单图形编程的学习(1)---文字 (Windows GDI实现)

简单图形编程的学习(1)---文字 (Windows GDI实现)

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

 

一、   全部简单图形编程的学习说在前面的话

      此系列文章均假设读者已经具备一定的对应的程序编写知识,无论是最简单的small basic,还是因为常用而被人熟知的Windows GDI,或者是Linux下用的更多的Qt(一般我用PyQt),甚至是现在国内知道的人并不多的Android,我都不准备讲太多基础的语法,或者与平台相关的太多背景知识,这些靠读者先行学习,我仅仅准备在自己学习的过程中找点乐子:)看看我用一些简单的接口都能想出干什么事情,然后展示给大家看看,图形程序实在是最好展示的一类程序了,不像其他程序一样,哪怕我讲了一堆的boost,真正见识到boost强大的又有几个呢?-_-!要知道,今天起,所有程序都是窗口程序,不再是命令行!!!!人类用了多久才走到这一步我不知道。。。。我用了25.......(从我出生算起)或者1年(从工作开始)

       另外,想要看怎么编写窗口应用程序的就不要走错地方了,这里不是想怎么描述怎么使用一个又一个的控件,这里都是讲绘图的-_-!

 

二、   谈谈Windows GDI

由于今天是第一篇,所以谈谈Windows GDI

虽然因为兴趣和工作需要,对Linux也有所了解,但是Windows到目前为止绝对是本人最熟悉的平台。。。也许也是绝大部分程序员最熟悉的平台吧,但是GDI用的实在是并不多。。。。也许又要说了。。我本质上是个服务器端的程序员-_-!呵呵,服务器端程序员每天面对的只能是控制台,与图形化界面无关,更加与GDI无关。。。。呵呵,但是假如要做客户端的话,是有图形界面了,但是其实游戏还是不需要用到GDI的。。。Windows下不都是用DirectX嘛。但是我对GDI还是比较有兴趣,主要来源于一个资深同事描述用Windows GDI去描述IM软件界面的往事(公司以前是做IM软件的),呵呵,我听着都觉得出神入化。自己好歹也了解一下,虽然说其实用到的机会不多。

文字好像都不像是图形编程中应该学习的东西,但是别忘了,文字可都是由象形文字发展过来的。。。中文至今还是象形文字呢,文字在远古的时代可本来就是图形啊,为啥学习图形编程的时候不要学习怎么显示文字啊?呵呵,前面的都是废话,其实你编点啥程序都会碰到需要在图形中显示文字的情况,所以我们先来看看文字的显示。另外,其实在显示文字的时候,假如需要对文字的显示进行设置,也能学到很多普通图形的设置方式,这点以后就能看到。

 

三、   Windows GDI的文字显示

事实上因为一个完整的Windows程序已经较为复杂,所以以后的程序得有个模板可以套才行,不然老是纠缠在窗口注册,创建和消息循环上了,那样效率太低。这里就用VS2005创建Win32程序本身的那一套了,不用MFC是不想拦住不了解也不像熟悉MFC的兄弟,也许另外弄个MFC+GDI+ (注:切分格式是(MFC+(GDI+))-_-!)篇吧。

基本程序如下:

// Win32GraphicEx1.cpp : 定义应用程序的入口点。

//

 

#include "stdafx.h"

#include "Win32GraphicEx1.h"

 

#define MAX_LOADSTRING 100

 

// 全局变量:

HINSTANCE hInst;                    // 当前实例

TCHAR szTitle[MAX_LOADSTRING];            // 标题栏文本

TCHAR szWindowClass[MAX_LOADSTRING];      // 主窗口类名

 

// 此代码模块中包含的函数的前向声明:

ATOM          MyRegisterClass(HINSTANCE hInstance);

BOOL          InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

 

int APIENTRY _tWinMain(HINSTANCE hInstance,

                     HINSTANCE hPrevInstance,

                     LPTSTR    lpCmdLine,

                     int       nCmdShow)

{

   UNREFERENCED_PARAMETER(hPrevInstance);

   UNREFERENCED_PARAMETER(lpCmdLine);

 

   // TODO: 在此放置代码。

   MSG msg;

   HACCEL hAccelTable;

 

   // 初始化全局字符串

   LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

   LoadString(hInstance, IDC_WIN32GRAPHICEX1, szWindowClass, MAX_LOADSTRING);

   MyRegisterClass(hInstance);

 

   // 执行应用程序初始化:

   if (!InitInstance (hInstance, nCmdShow))

   {

      return FALSE;

   }

 

   hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32GRAPHICEX1));

 

   // 主消息循环:

   while (GetMessage(&msg, NULL, 0, 0))

   {

      if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))

      {

         TranslateMessage(&msg);

        DispatchMessage(&msg);

      }

   }

 

   return (int) msg.wParam;

}

 

 

 

//

//  函数: MyRegisterClass()

//

//  目的: 注册窗口类。

//

//  注释:

//

//    仅当希望

//    此代码与添加到Windows 95 中的“RegisterClassEx”

//    函数之前的Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,

//    这样应用程序就可以获得关联的

//    格式正确的小图标。

//

ATOM MyRegisterClass(HINSTANCE hInstance)

{

   WNDCLASSEX wcex;

 

   wcex.cbSize = sizeof(WNDCLASSEX);

 

   wcex.style       = CS_HREDRAW | CS_VREDRAW;

   wcex.lpfnWndProc = WndProc;

   wcex.cbClsExtra     = 0;

   wcex.cbWndExtra     = 0;

   wcex.hInstance      = hInstance;

   wcex.hIcon       = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32GRAPHICEX1));

   wcex.hCursor     = LoadCursor(NULL, IDC_ARROW);

   wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);

   wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WIN32GRAPHICEX1);

   wcex.lpszClassName  = szWindowClass;

   wcex.hIconSm     = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

 

   return RegisterClassEx(&wcex);

}

 

//

//   函数: InitInstance(HINSTANCE, int)

//

//   目的: 保存实例句柄并创建主窗口

//

//   注释:

//

//        在此函数中,我们在全局变量中保存实例句柄并

//        创建和显示主程序窗口。

//

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

   HWND hWnd;

 

   hInst = hInstance; // 将实例句柄存储在全局变量中

 

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

 

   if (!hWnd)

   {

      return FALSE;

   }

 

   ShowWindow(hWnd, nCmdShow);

   UpdateWindow(hWnd);

 

   return TRUE;

}

 

//

//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)

//

//  目的: 处理主窗口的消息。

//

//  WM_COMMAND   - 处理应用程序菜单

//  WM_PAINT  - 绘制主窗口

//  WM_DESTROY   - 发送退出消息并返回

//

//

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

   int wmId, wmEvent;

   PAINTSTRUCT ps;

   HDC hdc;

 

   switch (message)

   {

   case WM_COMMAND:

      wmId    = LOWORD(wParam);

      wmEvent = HIWORD(wParam);

      // 分析菜单选择:

      switch (wmId)

      {

      case IDM_ABOUT:

        DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);

        break;

      case IDM_EXIT:

        DestroyWindow(hWnd);

        break;

      default:

        return DefWindowProc(hWnd, message, wParam, lParam);

      }

      break;

   case WM_PAINT:

      hdc = BeginPaint(hWnd, &ps);

      // TODO: 在此添加任意绘图代码...

      EndPaint(hWnd, &ps);

      break;

   case WM_DESTROY:

      PostQuitMessage(0);

      break;

   default:

      return DefWindowProc(hWnd, message, wParam, lParam);

   }

   return 0;

}

 

// “关于框的消息处理程序。

INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{

   UNREFERENCED_PARAMETER(lParam);

   switch (message)

   {

   case WM_INITDIALOG:

      return (INT_PTR)TRUE;

 

   case WM_COMMAND:

      if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)

      {

        EndDialog(hDlg, LOWORD(wParam));

        return (INT_PTR)TRUE;

      }

      break;

   }

   return (INT_PTR)FALSE;

}

 

以后讲解的时候可能就不列出完整的源代码了,因为用C++编写Win32程序,可能动辄几页的代码,完整列出影响阅读,为了完整,就如前面所言,我已经假定读者都具有相关领域一定的编程经验,将描述的代码放进恰当的位置应该不成问题。

文字的显示是个复杂的问题,(自有历史以来就复杂)不仅仅是调用几个类似于TextOutDrawText DrawTextEx API那么简单,看过Windows 图形编程》(参考1)的人应该会有同感,此书是我见过关于Windows下字体,文字显示最深入的一本书,(其实是其他的专著太深看不懂也没有看)。

至于Windows下普通的文字显示APIProgramming Windows》一书按照惯例还是最好的一本。

 

       Windows下最常用的文字输出API就是前面提到的3个,见下面的例子:

   case WM_PAINT:

      {

        hdc = BeginPaint(hWnd, &ps);

        // TextOut

        TextOut(hdc, 0, 0, szHelloWorld, (int)_tcslen(szHelloWorld));

 

        // DrawText

        RECT rtText = {0, 50, 100, 100};

        DrawText(hdc, szHelloWorld, -1, &rtText, DT_LEFT);

 

        // DrawTextEx

        rtText.top += 50;

        rtText.bottom += 50;

        DrawTextEx(hdc, szHelloWorld, -1, &rtText, DT_LEFT, NULL);

        EndPaint(hWnd, &ps);

      }

 

显示效果如插图1

 其实还有几个使用复杂度稍微高一点,但是控制力更强一些的文本输出函数,比如TabbedTextOut,ExtTextOut。(八卦一下:ExtTextOut是少有的将Ext放在函数名前表示扩展而不是按照微软惯例将Ex表示扩展放在函数名后的函数,估计是设计此函数的人刚到微软工作-_-!

 

四、   字体

其实字体是个更加复杂的问题。。。。有多少人知道在字体的现实问题上MS,Apple,Adobe的研究人员投入了多少精力啊。。。。今天的TrueType可不是一开始就存在的。。。。

当然,其实今天我们已经没有必要再去重复研究了,Windows下用MS提供的API就好了,一般有两个接口:

 

HFONT CreateFont(

  int nHeight,               // height of font

  int nWidth,                // average character width

  int nEscapement,           // angle of escapement

  int nOrientation,          // base-line orientation angle

  int fnWeight,              // font weight

  DWORD fdwItalic,           // italic attribute option

  DWORD fdwUnderline,        // underline attribute option

  DWORD fdwStrikeOut,        // strikeout attribute option

  DWORD fdwCharSet,          // character set identifier

  DWORD fdwOutputPrecision,  // output precision

  DWORD fdwClipPrecision,    // clipping precision

  DWORD fdwQuality,          // output quality

  DWORD fdwPitchAndFamily,   // pitch and family

  LPCTSTR lpszFace           // typeface name

);

这个接口直接通过超多的参数创建字体,看看参数的数量。。。就知道我说过的字体显示是个复杂问题没有错了。。。。

另外有个更加人性化的接口,那就是利用结构,本质上没有太大区别,只是从软件接口设计上来说,当参数超过67个的时候提供结构传递参数会更加人性化一点,CreateWindow之类的也就是遵循了这样的方式。这也是BSC++中不提供关键词参数,关键词参数没有那么重要的主要理由之一。(不明白我说的是什么那就忽略此句。。。见D&E6.5

所谓的用结构创建字体的接口如下:

HFONT CreateFontIndirect(

  CONST LOGFONT* lplf   // characteristics

);

LOGFONT结构就是前面一个直接创建的接口的参数的堆叠:

typedef struct tagLOGFONTW

{

    LONG      lfHeight;

    LONG      lfWidth;

    LONG      lfEscapement;

    LONG      lfOrientation;

    LONG      lfWeight;

    BYTE      lfItalic;

    BYTE      lfUnderline;

    BYTE      lfStrikeOut;

    BYTE      lfCharSet;

    BYTE      lfOutPrecision;

    BYTE      lfClipPrecision;

    BYTE      lfQuality;

    BYTE      lfPitchAndFamily;

    WCHAR     lfFaceName[LF_FACESIZE];

} LOGFONTW, *PLOGFONTW, NEAR *NPLOGFONTW, FAR *LPLOGFONTW;

 

这里列出来的是宽字节版本。参数如此之多,一方面体现了复杂度,一方面也是自由度,其实个人认为有点点设计的累赘了。。。。其实完全没有必要用一个一个整数来表示一个bool值的内容,MS习惯的位标志竟然在此处看不到痕迹。。。估计。。。写字体模块的哥们光研究怎么更好的显示字体了,没有关注接口的设计。。。。。或者,和写TabbedTextOut,ExtTextOut就是同一个人。。。。这个人很显然刚刚来微软。。。。

参数的含义不一个一个解释了,看MSDN或者《Programming Windows》,见下面一个例子,来自于《Programming Windows》。

 

/*---------------------------------------

   EZFONT.C -- Easy Font Creation

               (c) Charles Petzold, 1998

  ---------------------------------------*/

 

#include <windows.h>

#include <math.h>

#include "ezfont.h"

 

HFONT EzCreateFont (HDC hdc, TCHAR * szFaceName, int iDeciPtHeight,

                    int iDeciPtWidth, int iAttributes, BOOL fLogRes)

{

     FLOAT      cxDpi, cyDpi ;

     HFONT      hFont ;

     LOGFONT    lf ;

     POINT      pt ;

     TEXTMETRIC tm ;

    

     SaveDC (hdc) ;

    

     SetGraphicsMode (hdc, GM_ADVANCED) ;

     ModifyWorldTransform (hdc, NULL, MWT_IDENTITY) ;

     SetViewportOrgEx (hdc, 0, 0, NULL) ;

     SetWindowOrgEx   (hdc, 0, 0, NULL) ;

    

     if (fLogRes)

     {

          cxDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSX) ;

          cyDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSY) ;

     }

     else

     {

          cxDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, HORZRES) /

                                        GetDeviceCaps (hdc, HORZSIZE)) ;

         

          cyDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, VERTRES) /

                                        GetDeviceCaps (hdc, VERTSIZE)) ;

     }

    

     pt.x = (int) (iDeciPtWidth  * cxDpi / 72) ;

     pt.y = (int) (iDeciPtHeight * cyDpi / 72) ;

    

     DPtoLP (hdc, &pt, 1) ;

    

     lf.lfHeight         = - (int) (fabs (pt.y) / 10.0 + 0.5) ;

     lf.lfWidth          = 0 ;

     lf.lfEscapement     = 0 ;

     lf.lfOrientation    = 0 ;

     lf.lfWeight         = iAttributes & EZ_ATTR_BOLD      ? 700 : 0 ;

     lf.lfItalic         = iAttributes & EZ_ATTR_ITALIC    ?   1 : 0 ;

     lf.lfUnderline      = iAttributes & EZ_ATTR_UNDERLINE ?   1 : 0 ;

     lf.lfStrikeOut      = iAttributes & EZ_ATTR_STRIKEOUT ?   1 : 0 ;

     lf.lfCharSet        = DEFAULT_CHARSET ;

     lf.lfOutPrecision   = 0 ;

     lf.lfClipPrecision  = 0 ;

     lf.lfQuality        = 0 ;

     lf.lfPitchAndFamily = 0 ;

    

     lstrcpy (lf.lfFaceName, szFaceName) ;

    

     hFont = CreateFontIndirect (&lf) ;

    

     if (iDeciPtWidth != 0)

     {

          hFont = (HFONT) SelectObject (hdc, hFont) ;

         

          GetTextMetrics (hdc, &tm) ;

         

          DeleteObject (SelectObject (hdc, hFont)) ;

         

          lf.lfWidth = (int) (tm.tmAveCharWidth *

                                        fabs (pt.x) / fabs (pt.y) + 0.5) ;

         

          hFont = CreateFontIndirect (&lf) ;

     }

    

     RestoreDC (hdc, -1) ;

     return hFont ;

}

 

/*----------------------------------------

   FONTROT.C -- Rotated Fonts

                (c) Charles Petzold, 1998

  ----------------------------------------*/

 

#include <windows.h>

#include "ezfont.h"

 

TCHAR szAppName [] = TEXT ("FontRot") ;

TCHAR szTitle   [] = TEXT ("FontRot: Rotated Fonts") ;

 

void PaintRoutine (HWND hwnd, HDC hdc, int cxArea, int cyArea)

{

     static TCHAR szString [] = TEXT ("   Rotation") ;

     HFONT        hFont ;

     int          i ;

     LOGFONT      lf ;

 

     hFont = EzCreateFont (hdc, TEXT ("Times New Roman"), 540, 0, 0, TRUE) ;

     GetObject (hFont, sizeof (LOGFONT), &lf) ;

     DeleteObject (hFont) ;

 

     SetBkMode (hdc, TRANSPARENT) ;

     SetTextAlign (hdc, TA_BASELINE) ;

     SetViewportOrgEx (hdc, cxArea / 2, cyArea / 2, NULL) ;

 

     for (i = 0 ; i < 12 ; i ++)

     {

          lf.lfEscapement = lf.lfOrientation = i * 300 ;

          SelectObject (hdc, CreateFontIndirect (&lf)) ;

 

          TextOut (hdc, 0, 0, szString, lstrlen (szString)) ;

 

          DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;

     }

}

 

/*------------------------------------------------

   FONTDEMO.C -- Font Demonstration Shell Program

                 (c) Charles Petzold, 1998

  ------------------------------------------------*/

 

#include <windows.h>

#include "EzFont.h"

#include "resource.h"

 

extern  void     PaintRoutine (HWND, HDC, int, int) ;

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

 

HINSTANCE hInst ;

 

extern TCHAR szAppName [] ;

extern TCHAR szTitle [] ;

 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    PSTR szCmdLine, int iCmdShow)

{

     TCHAR    szResource [] = TEXT ("FontDemo") ;

     HWND     hwnd ;

     MSG      msg ;

     WNDCLASS wndclass ;

    

     hInst = hInstance ;

    

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

     wndclass.lpfnWndProc   = WndProc ;

     wndclass.cbClsExtra    = 0 ;

     wndclass.cbWndExtra    = 0 ;

     wndclass.hInstance     = hInstance ;

     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;

     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;

     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

     wndclass.lpszMenuName  = szResource ;

     wndclass.lpszClassName = szAppName ;

    

     if (!RegisterClass (&wndclass))

     {

          MessageBox (NULL, TEXT ("This program requires Windows NT!"),

                      szAppName, MB_ICONERROR) ;

          return 0 ;

     }

    

     hwnd = CreateWindow (szAppName, szTitle,

                          WS_OVERLAPPEDWINDOW,

                          CW_USEDEFAULT, CW_USEDEFAULT,

                          CW_USEDEFAULT, CW_USEDEFAULT,

                          NULL, NULL, hInstance, NULL) ;

    

     ShowWindow (hwnd, iCmdShow) ;

     UpdateWindow (hwnd) ;

    

     while (GetMessage (&msg, NULL, 0, 0))

     {

          TranslateMessage (&msg) ;

          DispatchMessage (&msg) ;

     }

     return msg.wParam ;

}

 

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     static DOCINFO  di = { sizeof (DOCINFO), TEXT ("Font Demo: Printing") } ;

     static int      cxClient, cyClient ;

     static PRINTDLG pd = { sizeof (PRINTDLG) } ;

     BOOL            fSuccess ;

     HDC             hdc, hdcPrn ;

     int             cxPage, cyPage ;

     PAINTSTRUCT     ps ;

    

     switch (message)

     {

     case WM_COMMAND:

          switch (wParam)

          {

          case IDM_PRINT:

 

                    // Get printer DC

 

               pd.hwndOwner = hwnd ;

          pd.Flags     = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;

 

             if (!PrintDlg (&pd))

                    return 0 ;

 

               if (NULL == (hdcPrn = pd.hDC))

               {

                    MessageBox (hwnd, TEXT ("Cannot obtain Printer DC"),

                                szAppName, MB_ICONEXCLAMATION | MB_OK) ;

                    return 0 ;

               }

                    // Get size of printable area of page

 

               cxPage = GetDeviceCaps (hdcPrn, HORZRES) ;

               cyPage = GetDeviceCaps (hdcPrn, VERTRES) ;

 

               fSuccess = FALSE ;

 

                    // Do the printer page

 

               SetCursor (LoadCursor (NULL, IDC_WAIT)) ;

               ShowCursor (TRUE) ;

 

               if ((StartDoc (hdcPrn, &di) > 0) && (StartPage (hdcPrn) > 0))

               {

                    PaintRoutine (hwnd, hdcPrn, cxPage, cyPage) ;

                   

                    if (EndPage (hdcPrn) > 0)

                    {

                         fSuccess = TRUE ;

                         EndDoc (hdcPrn) ;

                    }

               }

               DeleteDC (hdcPrn) ;

 

               ShowCursor (FALSE) ;

               SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

 

               if (!fSuccess)

                    MessageBox (hwnd,

                                TEXT ("Error encountered during printing"),

                                szAppName, MB_ICONEXCLAMATION | MB_OK) ;

               return 0 ;

 

          case IDM_ABOUT:

               MessageBox (hwnd, TEXT ("Font Demonstration Program/n")

                                 TEXT ("(c) Charles Petzold, 1998"),

                           szAppName, MB_ICONINFORMATION | MB_OK);

               return 0 ;

          }

          break ;

         

     case WM_SIZE:

          cxClient = LOWORD (lParam) ;

          cyClient = HIWORD (lParam) ;

          return 0 ;

         

     case WM_PAINT:

          hdc = BeginPaint (hwnd, &ps) ;

         

          PaintRoutine (hwnd, hdc, cxClient, cyClient) ;

         

          EndPaint (hwnd, &ps) ;

          return 0 ;

          

     case WM_DESTROY :

          PostQuitMessage (0) ;

          return 0 ;

     }

     return DefWindowProc (hwnd, message, wParam, lParam) ;

}

 

显示效果如插图2,一个显示成一圈的Rotation,用最最简单的手段实现绚烂的效果,以Small Basic中的一个星空显示文字的程序为最,这也算是比较突出的例子了。。。。

这里也不能老是抄袭Petzold。。。。。。。我将其转起来。实现旋转的动画:)

 

/*------------------------------------------------

   FONTDEMO.C -- Font Demonstration Shell Program

                 (c) 改自Charles Petzold, 1998,因为不知道其原来是啥版权,这里也不声明自己的版权了

  ------------------------------------------------*/

 

#include <windows.h>

#include "EzFont.h"

#include "resource.h"

 

extern void PaintRoutine (HWND, HDC, int, int) ;

extern void PaintAnimateOrientation(HWND hwnd, HDC hdc, int cxArea, int cyArea);

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

 

HINSTANCE hInst ;

 

 

extern TCHAR szAppName [] ;

extern TCHAR szTitle [] ;

 

#define WND_WIDTH (800)

#define WND_HEIGHT (800)

 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    PSTR szCmdLine, int iCmdShow)

{

   TCHAR    szResource [] = TEXT ("FontDemo") ;

   HWND     hwnd ;

   MSG      msg ;

   WNDCLASS wndclass ;

   HDC hdc ;

 

   hInst = hInstance ;

 

   wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

   wndclass.lpfnWndProc   = WndProc ;

   wndclass.cbClsExtra    = 0 ;

   wndclass.cbWndExtra    = 0 ;

   wndclass.hInstance     = hInstance ;

   wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;

   wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;

   wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

   wndclass.lpszMenuName  = szResource ;

   wndclass.lpszClassName = szAppName ;

 

   if (!RegisterClass (&wndclass))

   {

      MessageBox (NULL, TEXT ("This program requires Windows NT!"),

        szAppName, MB_ICONERROR) ;

      return 0 ;

   }

 

   hwnd = CreateWindow (szAppName, szTitle,

      WS_OVERLAPPEDWINDOW,

      CW_USEDEFAULT, CW_USEDEFAULT,

      WND_WIDTH, WND_HEIGHT,

      NULL, NULL, hInstance, NULL) ;

 

   ShowWindow (hwnd, iCmdShow) ;

   UpdateWindow (hwnd) ;

 

 

 

 

   while (TRUE)

   {

      // 就像游戏中一贯的做法

      if(PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))

      {

        if(msg.message == WM_QUIT)

        {

           break;

        }

 

        TranslateMessage (&msg);

        DispatchMessage (&msg);

      }

 

      hdc = GetDC(hwnd);

 

      PaintAnimateOrientation(hwnd, hdc, WND_WIDTH, WND_HEIGHT);

 

      ReleaseDC(hwnd, hdc);

   }

   return msg.wParam ;

}

 

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     static DOCINFO  di = { sizeof (DOCINFO), TEXT ("Font Demo: Printing") } ;

     static int      cxClient, cyClient ;

     static PRINTDLG pd = { sizeof (PRINTDLG) } ;

     BOOL            fSuccess ;

     HDC             hdc, hdcPrn ;

     int             cxPage, cyPage ;

     PAINTSTRUCT     ps ;

    

     switch (message)

     {

     case WM_COMMAND:

          switch (wParam)

          {

          case IDM_PRINT:

 

                    // Get printer DC

 

               pd.hwndOwner = hwnd ;

          pd.Flags     = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;

 

             if (!PrintDlg (&pd))

                    return 0 ;

 

               if (NULL == (hdcPrn = pd.hDC))

               {

                    MessageBox (hwnd, TEXT ("Cannot obtain Printer DC"),

                                szAppName, MB_ICONEXCLAMATION | MB_OK) ;

                    return 0 ;

               }

                    // Get size of printable area of page

 

               cxPage = GetDeviceCaps (hdcPrn, HORZRES) ;

               cyPage = GetDeviceCaps (hdcPrn, VERTRES) ;

 

               fSuccess = FALSE ;

 

                    // Do the printer page

 

               SetCursor (LoadCursor (NULL, IDC_WAIT)) ;

               ShowCursor (TRUE) ;

 

               if ((StartDoc (hdcPrn, &di) > 0) && (StartPage (hdcPrn) > 0))

               {

                    PaintRoutine (hwnd, hdcPrn, cxPage, cyPage) ;

                   

                    if (EndPage (hdcPrn) > 0)

                    {

                         fSuccess = TRUE ;

                         EndDoc (hdcPrn) ;

                    }

               }

               DeleteDC (hdcPrn) ;

 

               ShowCursor (FALSE) ;

               SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

 

               if (!fSuccess)

                    MessageBox (hwnd,

                                TEXT ("Error encountered during printing"),

                                szAppName, MB_ICONEXCLAMATION | MB_OK) ;

               return 0 ;

 

          case IDM_ABOUT:

               MessageBox (hwnd, TEXT ("Font Demonstration Program/n")

                                 TEXT ("(c) Charles Petzold, 1998"),

                           szAppName, MB_ICONINFORMATION | MB_OK);

               return 0 ;

          }

          break ;

         

     case WM_SIZE:

          cxClient = LOWORD (lParam) ;

          cyClient = HIWORD (lParam) ;

          return 0 ;

          

     case WM_PAINT:

          hdc = BeginPaint (hwnd, &ps) ;

         

         

          EndPaint (hwnd, &ps) ;

          return 0 ;

     case WM_DESTROY :

          PostQuitMessage (0) ;

          return 0 ;

     }

     return DefWindowProc (hwnd, message, wParam, lParam) ;

}

 

/*----------------------------------------

   FONTROT.C -- Rotated Fonts

                (c) 改自Charles Petzold, 1998

  ----------------------------------------*/

 

#include <windows.h>

#include <tchar.h>

#include "ezfont.h"

 

TCHAR szAppName [] = TEXT ("FontRot") ;

TCHAR szTitle   [] = TEXT ("FontRot: Rotated Fonts") ;

#define FRAME_PER_SECOND (20)

#define TIME_IN_FRAME (1000/FRAME_PER_SECOND)

 

#define WHITE_COLOR (RGB(255,255,255))

#define BLACK_COLOR (RGB(0,0,0))

void PaintRoutine (HWND hwnd, HDC hdc, int cxArea, int cyArea, int iAnimateOrientation)

{

   static TCHAR szString [] = TEXT ("   Rotation") ;

   HFONT        hFont ;

   int          i ;

   LOGFONT      lf ;

 

 

   hFont = EzCreateFont (hdc, TEXT ("Times New Roman"), 540, 0, 0, TRUE) ;

   GetObject (hFont, sizeof (LOGFONT), &lf) ;

   DeleteObject (hFont) ;

 

   SetBkMode (hdc, TRANSPARENT) ;

   SetTextAlign (hdc, TA_BASELINE) ;

   SetViewportOrgEx (hdc, cxArea / 2, cyArea / 2, NULL) ;

 

  

 

   SetTextColor(hdc, WHITE_COLOR);

   for (i = 0 ; i < 12 ; i++)

   {

      lf.lfEscapement = lf.lfOrientation = i * 300 + iAnimateOrientation-1;

      SelectObject (hdc, CreateFontIndirect (&lf)) ;

 

      TextOut (hdc, 0, 0, szString, lstrlen (szString)) ;

 

      DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;

   }

 

 

   SetTextColor(hdc, BLACK_COLOR);

   for (i = 0 ; i < 12 ; i++)

   {

      lf.lfEscapement = lf.lfOrientation = i * 300 + iAnimateOrientation;

      SelectObject (hdc, CreateFontIndirect (&lf)) ;

 

      TextOut (hdc, 0, 0, szString, lstrlen (szString)) ;

 

      DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;

   }

 

 

}

 

// By 九天雁翎:

// 主要的新添函数

void PaintAnimateOrientation(HWND hwnd, HDC hdc, int cxArea, int cyArea)

{

   DWORD dwStartTime;

   DWORD dwEndTime;

   DWORD dwInTime;

   int iIntervalTimeNeed ;

   static int iAnimateOrientation = 0;

 

   dwStartTime = GetTickCount();

 

 

   iAnimateOrientation += 1;

 

   PaintRoutine(hwnd, hdc, cxArea, cyArea, iAnimateOrientation);

// 帧数控制

   while(GetTickCount() - dwStartTime < TIME_IN_FRAME)

   {

      Sleep(1);

   }

 

}

 

其实目前的源代码中有个瑕疵,因为是用透明文字背景画图,用白色的文字覆盖原有文字的时候会出现一些覆盖不了的情况,这个情况导致文字转动后会留有一些背景的尾巴。。。。效果如插图3了,另外。。。之所以使用此种循环画图方式纯粹因为最近看了《Window游戏编程大师级技巧》一书,其实用纯timer的方式实现如此简单的动画应该也是可行的,并且因为可以依赖消息机制的背景刷新,就不会有此问题。见下面的改良版旋转文字动画:

SetBkMode (hdc, TRANSPARENT) ;一句改为SetBkMode (hdc, OPAQUE) ;倒是可以解决这个问题,但是因为背景的不透明,中间R重合的部分会导致互相的遮掩,这点没有深入研究了,希望有人能给出更好的解决方案。另外,因为是使用GDI,所以在每秒20帧重画的时候都会有闪烁。。。。。

 

改良版旋转文字动画:

/*------------------------------------------------

   FONTDEMO.C -- Font Demonstration Shell Program

                 (c) 改自Charles Petzold, 1998

  ------------------------------------------------*/

 

#include <windows.h>

#include "EzFont.h"

#include "resource.h"

 

void PaintRoutine (HWND hwnd, HDC hdc, int cxArea, int cyArea, int iAnimateOrientation);

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

 

HINSTANCE hInst ;

 

 

extern TCHAR szAppName [] ;

extern TCHAR szTitle [] ;

 

#define WND_WIDTH (800)

#define WND_HEIGHT (800)

 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    PSTR szCmdLine, int iCmdShow)

{

   TCHAR    szResource [] = TEXT ("FontDemo") ;

   HWND     hwnd ;

   MSG      msg ;

   WNDCLASS wndclass ;

   HDC hdc ;

 

   hInst = hInstance ;

 

   wndclass.style         = CS_HREDRAW | CS_VREDRAW ;

   wndclass.lpfnWndProc   = WndProc ;

   wndclass.cbClsExtra    = 0 ;

   wndclass.cbWndExtra    = 0 ;

   wndclass.hInstance     = hInstance ;

   wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;

   wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;

   wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;

   wndclass.lpszMenuName  = szResource ;

   wndclass.lpszClassName = szAppName ;

 

   if (!RegisterClass (&wndclass))

   {

      MessageBox (NULL, TEXT ("This program requires Windows NT!"),

        szAppName, MB_ICONERROR) ;

      return 0 ;

   }

 

   hwnd = CreateWindow (szAppName, szTitle,

      WS_OVERLAPPEDWINDOW,

      CW_USEDEFAULT, CW_USEDEFAULT,

      WND_WIDTH, WND_HEIGHT,

      NULL, NULL, hInstance, NULL) ;

 

   ShowWindow (hwnd, iCmdShow) ;

   UpdateWindow (hwnd) ;

 

   SetTimer(hwnd, 1, 50, NULL);

   // 主消息循环:

   while (GetMessage(&msg, NULL, 0, 0))

   {

      TranslateMessage(&msg);

      DispatchMessage(&msg);

   }

 

   return msg.wParam ;

}

 

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

   static DOCINFO  di = { sizeof (DOCINFO), TEXT ("Font Demo: Printing") } ;

   static int      cxClient, cyClient ;

   static PRINTDLG pd = { sizeof (PRINTDLG) } ;

   BOOL            fSuccess ;

   HDC             hdc, hdcPrn ;

   int             cxPage, cyPage ;

   PAINTSTRUCT     ps ;

   static int iAnimateOrientation = 0;

 

   switch (message)

   {

   case WM_COMMAND:

      switch (wParam)

      {

      case IDM_PRINT:

 

        // Get printer DC

 

        pd.hwndOwner = hwnd ;

        pd.Flags     = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION ;

 

        if (!PrintDlg (&pd))

           return 0 ;

 

        if (NULL == (hdcPrn = pd.hDC))

        {

           MessageBox (hwnd, TEXT ("Cannot obtain Printer DC"),

              szAppName, MB_ICONEXCLAMATION | MB_OK) ;

           return 0 ;

        }

        // Get size of printable area of page

 

        cxPage = GetDeviceCaps (hdcPrn, HORZRES) ;

        cyPage = GetDeviceCaps (hdcPrn, VERTRES) ;

 

         fSuccess = FALSE ;

 

        // Do the printer page

 

        SetCursor (LoadCursor (NULL, IDC_WAIT)) ;

        ShowCursor (TRUE) ;

 

        if ((StartDoc (hdcPrn, &di) > 0) && (StartPage (hdcPrn) > 0))

        {

           PaintRoutine (hwnd, hdcPrn, cxPage, cyPage, iAnimateOrientation) ;

 

           if (EndPage (hdcPrn) > 0)

           {

              fSuccess = TRUE ;

              EndDoc (hdcPrn) ;

           }

        }

        DeleteDC (hdcPrn) ;

 

        ShowCursor (FALSE) ;

        SetCursor (LoadCursor (NULL, IDC_ARROW)) ;

 

        if (!fSuccess)

           MessageBox (hwnd,

           TEXT ("Error encountered during printing"),

           szAppName, MB_ICONEXCLAMATION | MB_OK) ;

        return 0 ;

 

      case IDM_ABOUT:

        MessageBox (hwnd, TEXT ("Font Demonstration Program/n")

           TEXT ("(c) Charles Petzold, 1998"),

           szAppName, MB_ICONINFORMATION | MB_OK);

        return 0 ;

      }

      break ;

 

   case WM_SIZE:

      cxClient = LOWORD (lParam) ;

      cyClient = HIWORD (lParam) ;

      return 0 ;

 

   case WM_PAINT:

      hdc = BeginPaint (hwnd, &ps) ;

 

      PaintRoutine(hwnd, hdc, WND_WIDTH, WND_HEIGHT, iAnimateOrientation);

 

      EndPaint (hwnd, &ps) ;

      return 0 ;

   case WM_TIMER:

      {

        iAnimateOrientation += 1;

        InvalidateRect(hwnd, NULL, TRUE);

        return 0;

      }

 

   case WM_DESTROY :

      PostQuitMessage (0) ;

      return 0 ;

   }

   return DefWindowProc (hwnd, message, wParam, lParam) ;

}

 

#define BLACK_COLOR (RGB(0,0,0))

TCHAR szAppName [] = TEXT ("FontRot") ;

TCHAR szTitle   [] = TEXT ("FontRot: Rotated Fonts") ;

void PaintRoutine (HWND hwnd, HDC hdc, int cxArea, int cyArea, int iAnimateOrientation)

{

   static TCHAR szString [] = TEXT ("   Rotation") ;

   HFONT        hFont ;

   int          i ;

   LOGFONT      lf ;

 

 

   hFont = EzCreateFont (hdc, TEXT ("Times New Roman"), 540, 0, 0, TRUE) ;

   GetObject (hFont, sizeof (LOGFONT), &lf) ;

   DeleteObject (hFont) ;

 

   SetBkMode (hdc, TRANSPARENT) ;

   SetTextAlign (hdc, TA_BASELINE) ;

   SetViewportOrgEx (hdc, cxArea / 2, cyArea / 2, NULL) ;

 

   SetTextColor(hdc, BLACK_COLOR);

   for (i = 0 ; i < 12 ; i++)

   {

      lf.lfEscapement = lf.lfOrientation = i * 300 + iAnimateOrientation;

      SelectObject (hdc, CreateFontIndirect (&lf)) ;

 

      TextOut (hdc, 0, 0, szString, lstrlen (szString)) ;

 

      DeleteObject (SelectObject (hdc, GetStockObject (SYSTEM_FONT))) ;

   }

 

 

}

注意几个改动的地方,其实这个版本应该是最先的思路。。。。。。及利用TimerWindows消息机制来完成动画绘制,这样可以利用背景擦除消息来擦除背景,不需要重新自己用白色文字覆盖上一帧的文字,也不会有拖尾现象,但是,因为总是重复擦除然后重绘,所以会有闪烁。

 

另外,从理论上来说,直接将绘制放在擦除背景消息中,如下:

   case WM_PAINT:

      hdc = BeginPaint (hwnd, &ps) ;

 

      EndPaint (hwnd, &ps) ;

      return 0 ;

   case WM_ERASEBKGND:

      hdc = GetDC(hwnd);

      Rectangle(hdc, 0, 0, WND_WIDTH, WND_HEIGHT);

      PaintRoutine(hwnd, hdc, WND_WIDTH, WND_HEIGHT, iAnimateOrientation);

      ReleaseDC(hwnd, hdc);

      return 0;

闪烁会小一点,因为擦除背景到重新绘制的间隔更短了(放在WM_PAINT中还有个重新分配消息的过程),但是事实上看不怎么出来。

随机文字的那个例子比较简单,这里不再实现了。

 

五、   参考:

1. Windows 图形编程》第1415章(原版名《Windows Graphics Programming Win32 GDI and DirectDraw》,Feng Yuan著,机械工业出版社

2.Programming Windows Fifth EditionChapter4,17 Charles Petzold著,Microsoft Press

 

 

 

插图1:

 

 

插图3:

 

write by 九天雁翎(JTianLing) -- www.jtianling.com

阅读全文....

ubuntu 安装视频解码控件及文档

最近老在折腾ubuntu。。。。。呵呵,学习辛苦了,偶尔放松一下,对工作的环境(其实我主要工作还是在windows的VS中,Linux属于假想工作环境-_0!)

 

ubuntu由于有apt,deb包管理相当轻松,大部分任务就是sudo apt-get install XXXX,呵呵,实在是奇迹。。。。。

 

 

realplayer装了没有用。。。。原因不明。

 

国外的这个文章很牛:(http://www.ubuntugeek.com/install-mplayer-and-multimedia-codecs-libdvdcss2w32codecsw64codecs-in-ubuntu-904-jaunty.html

Install libdvdcss2 and w32 video codecs in Ubuntu 9.04 (Jaunty)

Support for WMV, RealMedia and other formats has been bundled into the w32codecs package. This package is not available from the Ubuntu repositories due to licensing and legal restrictions.To play encrypted DVDs, the libdvdcss2 package is essential.

For Ubuntu 9.04 (Jaunty) Users use the following procedures

sudo wget http://www.medibuntu.org/sources.list.d/jaunty.list --output-document=/etc/apt/sources.list.d/medibuntu.list

Then, add the GPG Key using the following commands

sudo apt-get update

For i386 Users install Codecs using the following command

sudo apt-get install medibuntu-keyring

sudo apt-get update

sudo apt-get install w32codecs libdvdcss2

For amd64 Users install Codecs using the following command

sudo apt-get install w64codecs libdvdcss2

Using above download locations you can install most of the mutimedia codecs for ubuntu.

Mplayer Plugin for Firefox

If you want to install Mplayer with plug-in for Mozilla Firefox run the following command

sudo apt-get install mozilla-mplayer

 

 

解决了很多问题

 

 

有个问题很有意思,现在我在windows下用kmplayer,感觉很好,很习惯,比windows下的mplayer还好用,还美观,现在改用了KDE(主要是因为学了QT的原因,其实我以前都是用Gnome),想都没有想,直接上在ubuntu上装kmplayer用,结果完全不好用,再查了查,还有个kplayer,还是不好用,都删掉,换成mplayer..............一切如以前般强大,接近无语。。。。。。

 

 

 

接着,开发库文档的问题:【转】

 

添加库函数手册
ubuntu默认是没有安装c语言的库函数man手册的,所以你在man perror 和sendto之类的函数时会显示没有相关文档的问题,这个问题让我郁闷了我好久。解决方法:
sudo apt-get install manpages-dev

 

事实上,也有中文版的文档了,只是看起来比较别扭(可能因为ubuntu的控制台下中文字不够美观)

 

选择man页面的方式是man 页面号 文档,比如我要查sleep的库函数调用,那就是man 3 sleep

阅读全文....

Ubuntu 9.04禁用触摸板的办法

现在将笔记本带到公司去了(好寒酸啊。。。。带着女朋友的HP520本本),装了Ubuntu9.04,这个本子很多地方设计不合理,其中USB的位置有问题,触摸板在打字的时候很容易误碰(对于敲程序来说太致命了),所以找了半天禁用的办法,流传最广的8.04下可用的例子已经不能用了,真的可用办法如下:

 

用 

sudo rmmod psmouse

禁用

要恢复也简单:
sudo modprobe psmouse 

 

 

 

来自

http://blog.3gcomet.com/trackback.asp?tbID=343&action=addtb&tbKey=627fe24937da2cebf94fe2f5a0b2022ebb428cbc

 

 

一切好了,哈雷路亚。。。。。。在Linux下没有不能做到的事情,只是看你知不知道怎么做。。。。。其实这个事情我折腾了很久。

阅读全文....

【转载】ubuntu搭建subversion(svn)服务器

关于普通的配置http://wiki.ubuntu.org.cn/SubVersion
中讲解的很详细

 

但是因为是做服务器,我希望开机即启动,这样排除手工干预,才能将服务器的显示器,鼠标,键盘省下来-_-!。。。

 

 

这里从别的网站转来的文章:(因为原来那个网站不厚道,没有出处,我也没有办法了,不是我不注明)

 

Ubuntu Add commentsubuntu预设是跑runleve2,也就是/etc/rc2.d内的软连结档,真正的服务设定档都在/etc/init.d当中。

 

我在/etc/rc2.d执行ls可以看得到firestarter,代表在开机时他的确有执行,事实上/etc/rc2.d到/etc/rc5.c应该都是一样的。

 

你也可以自行设定开机要跑哪一个runlevel。

 

可以试试这个套件:

 

$ sudo apt-get install sysvconfig

$ sudo sysvconfig

 

就可以设定开机服务。

 

 

 

其实上面的说法很简单,有点看不懂,基本思路是将服务器启动的脚本卸载/etc/init.d中,然后建立软连接(用ln -s)到/etc/rc2.d中去,这样就能那里面的启动脚本会在开机时自动运行,也就达到了我们要的开机运行效果。

 

阅读全文....