移植MiniGUI到S3C2410目标板

 

    网上看到的大多数是1.3版本的,1.6.10的基于FC系统的几乎没有。写下这篇文章,帮助那些刚接触minigui的同仁们。

 

 

环境

宿主机:FC6

目标板:arm 9,s 3c 2410, linux 2.6.24 .4

MiniGUI版本: 1.6.10   (http://www.minigui.org/res.shtml)

 

简介

 

    MiniGUI是北京飞漫公司的产品,号称遵循GPL条款。有关MiniGui的官方消息看

http://www.minigui.org (英文网站) http://www.minigui.cm(中文网站)。目前开源的最新版本是MiniGUI 1.6.10 。但是它的未开源的增值版已经到3.0了,增加了好多功能。

    主要代码包有

    libminigu- 1.6.10 .tar.gz :该文件是minigui的主要源文件。MiniGUI由三个函数库组成,libminigui,libmgext,libvcongui

    minigui-res- 1.6.10 .tar.gzminigui所使用的资源,包括字体,图标,位图,光标样式等。

mg-samples- 1.6.10 .tar.gz : <minigui编程指南>配套示例程序

mde- 1.6.10 .tar.gz : MiniGUI的综合演示程序包,有复杂示例。

 

交叉编译libminigui

    交叉编译工具链如何安装,请参阅其他文章,网上很多。本文用的是buildroot的编译工具链。它可使用uclibc库,更精简。

编译器版本:arm-linux-gcc (GCC) 3.4.2 uclibc库版本libuClibc-0.9.28。如果在下面的步骤中,出现一些编译问题,大多数是由于gcc版本和c库问题,请配置好自己的交叉编译工具链。

 

    首先要配置编译选项,在libminigui- 1.6.10 顶层目录下,通过使用configure脚本来进行相关的配置。运行configure脚本,会生成makefile文件,然后根据传递给configure脚本的各种选项来生成mgconfig.h文件。之后,运行makemake install命令,就可以编译MiniGUI并将MiniGUI的头文件和函数库安装到指定目录。

    看到网上很多关于老的minigui 1.3.3 版本的配置,都是使用make menuconfig ,而在新版里,已经不再通过这种方式来配置了,最好的方法是自己写脚本,来配置各选项。

    我的脚本如下:

       #!/bin/bash

rm config.cache config.status -f

CC=arm-linux-gcc /

CFLAGS=-I/usr/src/buildroot/build_arm/staging_dir/include /

./configure --prefix=/usr/local/minigui1.6.10/ /

--build=i386-linux /

--host=arm-unknown-linux /

--target=arm-unknown-linux /

下面解释脚本内容:

第一行rm –f 删除上次配置产生的文件。如果第一次配置,就不必了。为了保险,建议写上。

第二行CC=arm-linux-gcc  指定交叉编译器。请按照自己配置的交叉编译工具链来指定。

第三行 CFLAGS=-I/usr/src/buildroot/build_arm/staging_dir/include 编译选项。-I 指定编译器编译时使用的头文件路径。

第四行./configure --prefix=/usr/local/minigui 1.6.10 / 开始指定minigui的编译配置选项。

--prefix用于指定Minigui函数库的安装路径。默认安装路径是/usr/local,这里是/usr/local/minigui 1.6.10 ,那么在执行make ,make install之后,函数库,头文件和参考手册页被安装在/usr/local/minigui1.6.10/lib , /usr/local/minigui1.6.10/include , /usr/local/minigui1.6.10/man目录下。

第五行--build=i386-linux  指定软件包安装的系统平台,如果没有指定,默认值是’--host’选项的值。这里指本主机。

第六行 --host=arm-unknown-linux 指定软件运行的系统平台,如果没有指定,将会运行’config.guess’来检测,因为我们生成的minigui的函数库在arm平台上运行,则指定arm-unknown-linux

第七行--target=arm-unknown-linux 指定软件面向的系统平台。这主要在编译器和汇编器上下文中起作用。

上面都是Minigui的一些重要配置选项。当然Minigui不止这些配置,还有很多选项,其他选项都采用默认值了。至于默认值是啥,可以运行

$./configure –help

详细列出各种配置选项及默认值。

 

 

    运行该脚本之后, 产生makefile等几个文件。然后

make

make install

将函数库,头文件等安装到指定的路径中。

 

    以上步骤如果出错,请仔细查看config.log,里面有详细的出错原因。比如,没有创建文件夹,编译路径有错等等,一目了然。

如果没有出错,检查一下你的--prefix选项指定路径里是否有以下文件(本文在/usr/local/minigui 1.6.10 /下):

/usr/local/minigui 1.6.10 /lib:

lrwxrwxrwx 1 root root      22 09-04 13:47 libmgext-1.6.so.10 -> libmgext-1.6.so. 10.0.0

-rwxr-xr-x 1 root root  218882 09-04 13:47 libmgext-1.6.so. 10.0.0

-rw-r--r-- 1 root root  240436 09-04 13:47 libmgext.a

-rwxr-xr-x 1 root root     743 09-04 13:47 libmgext.la

lrwxrwxrwx 1 root root      22 09-04 13:47 libmgext.so -> libmgext-1.6.so. 10.0.0

lrwxrwxrwx 1 root root      24 09-04 13:47 libminigui-1.6.so.10 -> libminigui-1.6.so. 10.0.0

-rwxr-xr-x 1 root root 1811526 09-04 13:47 libminigui-1.6.so. 10.0.0

-rw-r--r-- 1 root root 2029908 09-04 13:47 libminigui.a

-rwxr-xr-x 1 root root     757 09-04 13:47 libminigui.la

lrwxrwxrwx 1 root root      24 09-04 13:47 libminigui.so -> libminigui-1.6.so. 10.0.0

lrwxrwxrwx 1 root root      24 09-04 13:47 libvcongui-1.6.so.10 -> libvcongui-1.6.so. 10.0.0

-rwxr-xr-x 1 root root   73670 09-04 13:47 libvcongui-1.6.so. 10.0.0

-rw-r--r-- 1 root root   68716 09-04 13:47 libvcongui.a

-rwxr-xr-x 1 root root     757 09-04 13:47 libvcongui.la

lrwxrwxrwx 1 root root      24 09-04 13:47 libvcongui.so -> libvcongui-1.6.so.10

 

/usr/local/minigui 1.6.10 /include/minigui:

colordlg.h    dti.c        gdi.h        newfiledlg.h         own_stdio.h        threadx_semaphore.h  vxworks_semaphore.h  window.h

colorspace.h  endianrw.h   mgconfig.h   nucleus_pthread.h    psos_pthread.h     ucos2_pthread.h      win32_dirent.h

common.h      ext          mgext.h      nucleus_semaphore.h  psos_semaphore.h   ucos2_semaphore.h    win32_pthread.h

control.h     filedlg.h    minigui.h    ose_semaphore.h      skin.h             vcongui.h            win32_sched.h

ctrl          fixedmath.h  mywindows.h  own_malloc.h         threadx_pthread.h  vxworks_pthread.h    win32_semaphore.h

 

    还有一个重要的配置文件/usr/local/minigui 1.6.10 /etc/MiniGUI.cfg,没有这个文件,编译后的程序在板子上也无法执行的。当然,这个文件不能直接使用,还需修改,后面会讲到。

 

完成上面的步骤,已经不知不觉成功了大半了。

 

安装minigui资源库

GUI里包含很多图标,样式,这些都需要资源库。下面一起装上minigui的资源库

解压minigui-res- 1.6.10 .tar.gz

进入minigui-res- 1.6.10 目录

make install

则资源文件都被装到/usr/local/lib/minigui/res下。(这一步,其实也不需要make install,后面用到资源,直接复制到板上根文件系统相应目录中即可。)

 

编译运行minigui的应用程序

    网上文章里的helloworld示例,用minigui 1.6.10 库,已经无法编译通过,库函数结构有了很大不同。我们可以从minigui的示例包中找个文件来进行编译。如

 

  1. animation.c
  2. /* 
  3. ** $Id: animation.c,v 1.12 2007-08-30 01:20:10 xwyan Exp $
  4. **
  5. ** Listing 36.1
  6. **
  7. ** animation.c: Sample program for MiniGUI Programming Guide
  8. **      Usage of ANIMATION control and GIF89a loader.
  9. **
  10. ** Copyright (C) 2004 ~ 2007 Feynman Software.
  11. **
  12. ** License: GPL
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <minigui/common.h>
  18. #include <minigui/minigui.h>
  19. #include <minigui/gdi.h>
  20. #include <minigui/window.h>
  21. #include <minigui/control.h>
  22. #include <minigui/mgext.h>
  23. static const char* filename = "9.gif";
  24. int ret;
  25. static ANIMATION* anim = NULL;
  26. static int AnimationWinProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
  27. {
  28.     switch (message) {
  29.     case MSG_CREATE:
  30.     {
  31.         anim = CreateAnimationFromGIF89aFile (HDC_SCREEN, filename);
  32.         if (anim == NULL)
  33.             return 1;
  34.         SetWindowAdditionalData (hWnd, (DWORD) anim);
  35.         CreateWindowEx (CTRL_ANIMATION, 
  36.                           ""
  37.                           WS_VISIBLE | ANS_AUTOLOOP | ANS_SCALED, 
  38.                           WS_EX_TRANSPARENT,
  39.                           100, 
  40.                           50, 10, 120, 60, hWnd, (DWORD)anim);
  41.         SendMessage (GetDlgItem (hWnd, 100), ANM_STARTPLAY, 0, 0);
  42.         CreateWindowEx (CTRL_ANIMATION, 
  43.                           ""
  44.                           WS_VISIBLE | ANS_AUTOLOOP | ANS_FITTOANI,
  45.                           WS_EX_TRANSPARENT,
  46.                           200, 
  47.                           50, 160, 120, 60, hWnd, (DWORD)anim);
  48.         break;
  49.     }
  50.     case MSG_LBUTTONDOWN:
  51.         SendMessage (GetDlgItem (hWnd, 200), ANM_SETANIMATION, 0, (LPARAM)anim);
  52.         SendMessage (GetDlgItem (hWnd, 200), ANM_STARTPLAY, 0, 0);
  53.        break;
  54.     case MSG_DESTROY:
  55.         DestroyAnimation ((ANIMATION*)GetWindowAdditionalData (hWnd), TRUE);
  56.         DestroyAllControls (hWnd);
  57.         return 0;
  58.     case MSG_CLOSE:
  59.         ret = PostQuitMessage (hWnd);
  60.         DestroyMainWindow (hWnd);
  61.         return 0;
  62.     }
  63.     return DefaultMainWinProc(hWnd, message, wParam, lParam);
  64. }
  65. int MiniGUIMain (int argc, const char* argv[])
  66. {
  67.     MSG Msg;
  68.     HWND hMainWnd;
  69.     MAINWINCREATE CreateInfo;
  70.     if (argc >= 2)
  71.         filename = argv[1];
  72. #ifdef _MGRM_PROCESSES
  73.     JoinLayer(NAME_DEF_LAYER , "animation" , 0 , 0);
  74. #endif
  75.     if (!InitMiniGUIExt()) {
  76.         return 1;
  77.     }
  78.     CreateInfo.dwStyle = WS_CAPTION | WS_BORDER | WS_VISIBLE;
  79.     CreateInfo.dwExStyle = WS_EX_NONE;
  80. #ifdef _LANG_ZHCN
  81.     CreateInfo.spCaption = "动画控件" ;
  82. #else
  83.     CreateInfo.spCaption = "Animation Control" ;
  84. #endif
  85.     CreateInfo.hMenu = 0;
  86.     CreateInfo.hCursor = GetSystemCursor (IDC_ARROW);
  87.     CreateInfo.hIcon = 0;
  88.     CreateInfo.MainWindowProc = AnimationWinProc;
  89.     CreateInfo.lx = 0; 
  90.     CreateInfo.ty = 0;
  91.     CreateInfo.rx = 240;//GetGDCapability(HDC_SCREEN, GDCAP_HPIXEL);
  92.     CreateInfo.by = 300;//GetGDCapability(HDC_SCREEN, GDCAP_VPIXEL);
  93.     CreateInfo.iBkColor = PIXEL_lightgray;
  94.     CreateInfo.dwAddData = 0;
  95.     CreateInfo.dwReserved = 0;
  96.     CreateInfo.hHosting = HWND_DESKTOP;
  97.     hMainWnd = CreateMainWindow (&CreateInfo);
  98.     if (hMainWnd == HWND_INVALID)
  99.         return -1;
  100.     ShowWindow (hMainWnd, SW_SHOWNORMAL);
  101.     while (GetMessage(&Msg, hMainWnd)) {
  102.         TranslateMessage(&Msg);
  103.         DispatchMessage(&Msg);
  104.     }
  105.     MainWindowThreadCleanup (hMainWnd);
  106.     MiniGUIExtCleanUp ();
  107.     return 0;
  108. }
  109. #ifndef _LITE_VERSION
  110. #include <minigui/dti.c>
  111. #endif

    上面的程序用如下命令编译:

$arm-linux-gcc -I/usr/local/minigui 1.6.10 /include -L/usr/local/minigui1.6.10/lib -O2 -o animation animation.c -lminigui -lmgext -lm -ljpeg -lpthread

    如果出现未定义的函数名,则检查相关库文件是否存在或者库文件版本是否兼容。这里用到的库文件有libc,libminigui,libmgext,libm,libjpeg,libpthread

如果你的交叉编译工具链的库目录里缺少这些库,则参考网上其他文章,建立这些库。minigui 1.6.10 的下载页面上也提供了这些依赖工具。

如果编译未发现错误,那么恭喜你,你马上就会享受成功的喜悦了。

 

    要在板上运行该编译好的程序,还需要做一些准备工作。

    首先,将上面生成的库文件放到板上根文件系统lib目录中。动态编译的程序,需要依赖这些库文件,少了则无法运行。

    有了库文件,还不够,还需要资源文件。资源文件放在/usr/local/lib/minigui/res里,读者也可根据自己习惯放置,但是在MiniGUI的配置里一定要指定到正确的路径,否则会找不到资源而报错。

另外,还需要MiniGUI的配置文件。这里要注意的是1.3.x的配置文件放在/usr/local,1.6.x的配置文件是放在/etc/下的。要想适合目标板环境,MiniGUI.cfg文件内容需要修改。修改如下:

# MiniGUI Ver 2.0.3 /1.6.9

# This configuration file is for classic window style.

#

# Copyright (C) 2002~2007 Feynman Software

# Copyright (C) 1998~2002 Wei Yongming.

#

# Web:   http://www.minigui.com

# Web:   http://www.minigui.org

#

# This configuration file must be installed in /etc,

# /usr/local/etc or your home directory. When you install it in your

# home directory, it should be named ".MiniGUI.cfg".

#

# The priority of above configruation files is ~/.MiniGUI.cfg,

# /usr/local/etc/MiniGUI.cfg, and then /etc/MiniGUI.cfg.

#

# If you change the install path of MiniGUI resource, you should

# modify this file to meet your configuration.

#

# NOTE:

# The format of this configuration file has changed since the last release.

# Please DONT forget to provide the latest MiniGUI.cfg file for your MiniGUI.

#

 

[system]

# GAL engine and default options

gal_engine=fbcon

defaultmode=320x240-16bpp

 

# IAL engine

ial_engine=dummy

mdev=/dev/input/mice

mtype=IMPS2

 

[fbcon]

defaultmode=320x240-16bpp

 

[qvfb]

defaultmode=640x480-16bpp

display=0

 

# The first system font must be a logical font using RBF device font.

[systemfont]

font_number=6

font0=rbf-fixed-rrncnn-8-16-ISO8859-1

font1=*-fixed-rrncnn-*-16-GB2312

font2=*-Courier-rrncnn-*-16-GB2312

font3=*-SansSerif-rrncnn-*-16-GB2312

font4=*-Times-rrncnn-*-16-GB2312

font5=*-Helvetica-rrncnn-*-16-GB2312

 

default=0

wchar_def=1

fixed=1

caption=2

menu=3

control=3

 

[rawbitmapfonts]

font_number=4

name0=rbf-fixed-rrncnn-8-16-ISO8859-1

fontfile0=/usr/local/lib/minigui/res/font/8x16-iso8859-1.bin

name1=rbf-fixed-rrncnn-16-16-GB2312-0

fontfile1=/usr/local/lib/minigui/res/font/song-16-gb2312.bin

name2=rbf-fixed-rrncnn-6-12-ISO8859-1

fontfile2=/usr/local/lib/minigui/res/font/6x12-iso8859-1.bin

name3=rbf-fixed-rrncnn-12-12-GB2312-0

fontfile3=/usr/local/lib/minigui/res/font/song-12-gb2312.bin

 

[varbitmapfonts]

font_number=6

name0=vbf-Courier-rrncnn-8-13-ISO8859-1

fontfile0=/usr/local/lib/minigui/res/font/Courier-rr-8-13.vbf

name1=vbf-Helvetica-rrncnn-11-12-ISO8859-1

fontfile1=/usr/local/lib/minigui/res/font/Helvetica-rr-11-12.vbf

name2=vbf-Times-rrncnn-10-12-ISO8859-1

fontfile2=/usr/local/lib/minigui/res/font/Times-rr-10-12.vbf

name3=vbf-Courier-rrncnn-10-15-ISO8859-1

fontfile3=/usr/local/lib/minigui/res/font/Courier-rr-10-15.vbf

name4=vbf-Helvetica-rrncnn-15-16-ISO8859-1

fontfile4=/usr/local/lib/minigui/res/font/Helvetica-rr-15-16.vbf

name5=vbf-Times-rrncnn-13-15-ISO8859-1

fontfile5=/usr/local/lib/minigui/res/font/Times-rr-13-15.vbf

 

[qpf]

font_number=3

name0=qpf-unifont-rrncnn-16-16-ISO8859-1,ISO8859-15,GB2312-0,GBK,BIG5

fontfile0=/usr/local/lib/minigui/res/font/unifont_160_50.qpf

name1=qpf-times-rrncnn-5-10-ISO8859-1,ISO8859-15

fontfile1=/usr/local/lib/minigui/res/font/smoothtimes_100_50.qpf

name2=qpf-helvetica-rrncnn-5-10-ISO8859-1,ISO8859-15

fontfile2=/usr/local/lib/minigui/res/font/helvetica_100_50.qpf

name3=qpf-micro-rrncnn-4-4-ISO8859-1,ISO8859-15

fontfile3=/usr/local/lib/minigui/res/font/micro_40_50.qpf

 

[truetypefonts]

font_number=3

name0=ttf-arial-rrncnn-0-0-ISO8859-1

fontfile0=/usr/local/lib/minigui/res/font/arial.ttf

name1=ttf-times-rrncnn-0-0-ISO8859-1

fontfile1=/usr/local/lib/minigui/res/font/times.ttf

name2=ttf-pinball-rrncnn-0-0-ISO8859-1

fontfile2=/usr/local/lib/minigui/res/font/pinball.ttf

 

[type1fonts]

font_number=0

name0=type1-Charter-rrncnn-0-0-ISO8859-1

fontfile0=/usr/local/lib/minigui/res/font/bchr.pfb

name1=type1-Charter-rincnn-0-0-ISO8859-1

fontfile1=/usr/local/lib/minigui/res/font/bchri.pfb

name2=type1-Charter-brncnn-0-0-ISO8859-1

fontfile2=/usr/local/lib/minigui/res/font/bchb.pfb

name3=type1-Charter-bincnn-0-0-ISO8859-1

fontfile3=/usr/local/lib/minigui/res/font/bchbi.pfb

name4=type1-Courier-rrncnn-0-0-ISO8859-1

fontfile4=/usr/local/lib/minigui/res/font/dcr10.pfb

name5=type1-Courier-rincnn-0-0-ISO8859-1

fontfile5=/usr/local/lib/minigui/res/font/dcti10.pfb

name6=type1-Courier-brncnn-0-0-ISO8859-1

fontfile6=/usr/local/lib/minigui/res/font/dcbx10.pfb

name7=type1-Courier-bincnn-0-0-ISO8859-1

fontfile7=/usr/local/lib/minigui/res/font/dcbxti10.pfb

name8=type1-eufm10-rrncnn-0-0-ISO8859-1

fontfile8=/usr/local/lib/minigui/res/font/eufm10.pfb

 

[mouse]

dblclicktime=300

 

[event]

timeoutusec=300000

repeatusec=50000

 

[cursorinfo]

# Edit following line to specify cursor files path

cursorpath=/usr/local/lib/minigui/res/cursor/

cursornumber=23

cursor0=d_arrow.cur

cursor1=d_beam.cur

cursor2=d_pencil.cur

cursor3=d_cross.cur

cursor4=d_move.cur

cursor5=d_sizenwse.cur

cursor6=d_sizenesw.cur

cursor7=d_sizewe.cur

cursor8=d_sizens.cur

cursor9=d_uparrow.cur

cursor10=d_none.cur

cursor11=d_help.cur

cursor12=d_busy.cur

cursor13=d_wait.cur

cursor14=g_rarrow.cur

cursor15=g_col.cur

cursor16=g_row.cur

cursor17=g_drag.cur

cursor18=g_nodrop.cur

cursor19=h_point.cur

cursor20=h_select.cur

cursor21=ho_split.cur

cursor22=ve_split.cur

 

[iconinfo]

# Edit following line to specify icon files path

iconpath=/usr/local/lib/minigui/res/icon/

# Note that max number defined in source code is 5.

iconnumber=5

icon0=form.ico

icon1=failed.ico

icon2=mg_help.ico

icon3=warning.ico

icon4=excalmatory.ico

 

# default icons for TREEVIEW control

fold=fold.ico

unfold=unfold.ico

 

# default icons for new OpenFileDialogBox

dir=folder.ico

file=textfile.ico

    特别注意红字部分。本人目标板的液晶屏使用320*240 16bpp模式。GAL引擎选择fbcon

这样将MiniGUI.cfg放到板上根文件系统/etc/下后,一切就绪,运行程序。哦,是不是提示少了9.gif?直接将9.gif放在程序所在目录即可。

漂亮的动画动起来了。看到这画面,是不是有种成功的喜悦?

      

    注:对于板上运行的linux系统,需要支持FrameBuffer,如果您不确定,请参见我的另一篇文章《移植LCD驱动到S 3C 2410上》。

 

 

错误汇总:

 

1. FC6安装qvfb  (主机下运行Minigui,按照版本 1.3.3 安装,一般没有太大的问题)

如果出现checking for Qt... configure: error: Qt (>= Qt 3.0.3 ) (headers and libraries) not found. Please check your installation!

For more details about this problem, look at the end of config.log.

 

解决:检查/usr/lib下是否有qt的库。如果有,还出现上面的提示,可能是没有安装开发版的qt,需要重新安装qt-dev版,将qt的库装全。

 

2.提示:

# ./animation

GDI: Error in loading raw bitmap fonts!

GDI: Can not initialize raw bitmap fonts!

InitGUI: Initialization of GDI failure!

InitGUI failure when using /etc/MiniGUI.cfg as cfg file.

 

原因:装载错误。minigui没有找到资源文件。

查看MiniGui.cfg内容,配置资源路径如下:

[rawbitmapfonts]

font_number=4

name0=rbf-fixed-rrncnn-8-16-ISO8859-1

fontfile0=/usr/local/lib/minigui/res/font/8x16-iso8859-1.bin

name1=rbf-fixed-rrncnn-16-16-GB2312-0

fontfile1=/usr/local/lib/minigui/res/font/song-16-gb2312.bin

name2=rbf-fixed-rrncnn-6-12-ISO8859-1

fontfile2=/usr/local/lib/minigui/res/font/6x12-iso8859-1.bin

name3=rbf-fixed-rrncnn-12-12-GB2312-0

fontfile3=/usr/local/lib/minigui/res/font/song-12-gb2312.bin

从上面可知,Minigui的资源应该放在/usr/local/lib/minigui/res下。

解决: 将资源文件拷贝到相应目录,复制粘贴即可。

 

3. 提示:IAL: Does not find the request engine: SMDK2410.

IAL: Use the first engine: dummy

原因:目标板输入系统未配置。

Dummy输入引擎(哑输入引擎),不和任何实际的输入设备相关联,因此不会产生任何输入。在目标板输入引擎没准备好之前,可以使用dummy输入引擎来运行minigui。当minigui根据配置找不到匹配的输入引擎时,会自动选择dummy输入引擎。

解决:修改MiniGUI.cfg文件,见上。

 

    因本人水平和写文章时间仓促,以上内容,难免有遗漏,错误和不妥之处,恳请广大读者批评指正。我的联系方式:zealane@gmail.com 我的博客:http://blog.csdn.net/flylonginsky

我的开源项目:http://code.google.com/p/homer2/  欢迎交流讨论。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值