curses函数库简介及使用

news2024/11/26 1:59:31

curses函数库简介及使用

  • 导语
  • curses简介
  • 屏幕
    • 输出
    • 读取
    • 清除
    • 移动
    • 字符
  • 键盘
    • 键盘模式
    • 输入
  • 窗口
    • WINDOW
    • 常用函数
    • 屏幕刷新优化
  • 子窗口
  • keypad
  • 彩色显示
  • pad
  • 总结
  • 参考文献

导语

curses函数库主要用来实现对屏幕和光标的操作,它的功能定位处于简单文本行程序和完全图形化界面之间,在目前图形化界面已经蓬勃发展的现在可能显得有些过时,但是其中很多实现思想和操作仍然值得学习和借鉴,并且curses目前仍然是linux图形化编程的选择之一

curses简介

curses是一个函数库,它提供了许多对光标和终端屏幕的接口函数,在使用的时候必须包括对应的头文件函数声明和宏定义,并且用-lcurses进行定义,有些linux系统因为没有带相关的包,还需要安装类似libncurses5-dev的包

curses工作在屏幕、窗口和子窗口上,对于一个curses窗口,它一般被称为stdscr,与物理屏幕的尺寸一样,当然也可以创造一些别的尺寸小于当前屏幕的窗口,curses用两个ds来映射终端屏幕,stdscr和curscr,前者和stdout非常类似,是curses程序中的默认输出窗口,curscr和stdscr类似,对应的时当前屏幕的样子,需要注意的是,在程序调用refresh之前,输出到stdscr的内容不会显示在屏幕上,stdscr更像一个缓存,暂时存储一些改变

在调用refresh时,curses会比较stdscr和curscr(屏幕预状态和当前状态)之间的异同,之后根据差异刷新屏幕

一般来说,curses刷新逻辑屏幕的频率比刷新物理频率高,这很好理解,可以用计组中cache和内存之间的关系来类比,只有在程序执行的某些阶段,用户需要看到全部结果时,curses才会通过refresh计算出逻辑和物理之间对应的最佳途径,换句话说,curses只把最后的逻辑结果传递给物理屏幕

逻辑屏幕的布局是一个二维数组,每个位置不仅包含字符,还包含它的属性(例如粗体和下划线等),由于curses函数在使用的时候需要创建和删除一些临时ds,所以所有curses程序在开始使用前必须初始化,然后在结束使用之后恢复,通过initscr和endwin函数实现

屏幕

所有调用curses函数的程序必须以initscr和endwin结束,前者只能调用一次,成功则返回stdscr指针,否则返回错误信息,后者成功返回OK,失败返回ERR

输出

curses函数库有很多刷新屏幕的基本函数,书上很多,这里摘录并解释一些常用的函数,需要注意的是chtype是curses自己的字符类型,比标准char有更多位

int addch(const chtype char_to_add);
//在当前位置添加指定的字符
int printw(char *format);
//在光标位置输出,用法和printf一样
int refresh(void);
//刷新屏幕
int box(WINDOW *win_ptr, chtype vertical_char, chtype horizontal_char);
//围绕一个窗口画框,横竖用给定的字符
int insch(chtype char_to_insert);
//插入字符,将已有字符右移,准确来说是头插

读取

从屏幕上读取字符并不常用,但curses还是提供了对应的函数

chtype inch(void);
//返回光标当前位置字符和属性信息
int instr(char *string);
//返回字符串,写入string
int innstr(char *string,int number_of_characters);
//同上,但指定长度

清除

curses提供了四种清楚区域的方法,具体如下

int erase(void);
//在屏幕每个位置写上空白字符
int clear(void);
//彻底清除屏幕
int clrtobot(void);
//清除光标到屏幕尾
int clrtoeol(void);
//清除光标到当前行尾

移动

curses对光标的操作给的很少,只有两个函数,具体如下

int move(int new_y,int new_x);
//将逻辑光标移到指定地点,有外部整数LINES和COLUMNS
//并不会移动物理光标,需要移动则要用refresh
int leaveok(WINDOW *window_ptr,bool leave_flag);
//设置标志,控制屏幕刷新后物理光标的位置,0则和逻辑光标一样否则随机

字符

先前已经提到过,cureses中的每个字符是有属性的,这些属性是用宏来定义的,当需要修改时,直接使用这些宏作为对应参数给到函数即可,一些相关函数具体如下

int attron/attroff/attrset(chtype attribute);
//set是设置,on和off是开关
int standout/standend(void);
//反色显示

书上给出了一个例子,下面是代码和运行结果

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <curses.h>
int main()
{
    const char one[]=" First Witch ";
    const char two[]=" Second Witch ";
    initscr();
    move(5,15);
    attron(A_BOLD);//设置模式
    printw("%s","Bold test");//加粗输出
    attroff(A_BOLD);
    refresh();//刷新
    sleep(1);

    move(8,15);
    attron(A_STANDOUT);//设置模式
    printw("%s","test light");
    attroff(A_STANDOUT);//关闭反色
    refresh();
    sleep(1);

    move (10,10);//设置位置输出
    printw("%s","test sentence 1");
    move (11,13);
    printw("%s","test sentence 2");
    move(13,10);
    printw("%s","test sentence 3");
    move (14,23);
    printw("%s","test sentence 4");
    refresh();
    sleep(1);

    attron(A_DIM);
    int len=strlen(one);
    for(int i=len-1;i>=0;i--)//倒序插入
    {
        move(10,10);
        insch(one[i]);
    }
    len=strlen(two);
    for(int i=len-1;i>0;i--)
    {
        move(13,10);
        insch(two[i]);
    }

    attroff(A_DIM);
    refresh();
    sleep(1);

    move(LINES-1,COLS-1);
    refresh();
    sleep(5);
    endwin();
    return 0;
}

可以看到加粗、反色和其他效果的字符串是什么样的

在这里插入图片描述

键盘

除了屏幕之外,curses还有针对键盘的一系列接口

键盘模式

在curses中有许多模式,例如预处理,默认输入等,在使用initscr时,输入模式处于预处理模式,只有在用户按下回车之后,输入的数据才会被传给程序(键盘的特殊字符被启用,组合键可产生信号),如果程序调用cbreak就可以将输入模式设置为cbreak模式,字符一经键入就被立刻传递给程序(特殊字符启用,一些简单字符直传)

一些相关的函数如下

int echo/noecho(void);
//启用/不启用回显
int cbreak/nocbreak(void);
//启用/不启用cbreak
int raw/noraw(void);
//启用/不启用特殊字符的处理

输入

一些读取键盘输入的函数具体如下

int getch(void);
//类似getchar
int getstr(char* string);
//类似gets
int getnstr(char* string,int number_of_characters);
//类似getnstr
int scanw(char* format,...);
//类似scanf

书上给出的一个具体的例子如下

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <unistd.h>
int main()
{
    char name[256],pw[256];
    const char* rpw="1111";//真正的密码,用来检测
    initscr();//开模式
    move(5,10);
    printw("%s","login:");

    move(7,10);
    printw("%s","user name:");
    getstr(name);//拿用户名
 
    move(8,10);
    printw("%s","password:");

    cbreak();
    noecho();//关闭回显

    memset(pw,0,sizeof(pw));
    for(int i=0; i<256; i++)
    {
        pw[i]=getch();
        if(pw[i]=='\n')break;
        move(8,20+i);
        addch('*');//把输入的对应位置插入*
        refresh();
    }

    echo();
    nocbreak();

    move(11,10);
    if(strncmp(rpw,pw,strlen(rpw)))
        printw("%s","wrong");
    else
        printw("%s","correct");
    refresh();
    sleep(2);

    endwin();
    return 0;
}

可以看到,这个例子实现了一个简单的密码隐藏和检测的功能,通过调用curses和设置光标的位置来实现

在这里插入图片描述

窗口

curses可以在物理屏幕上同时显示多个不同尺寸的窗口,而不仅仅是对单一窗口进行操控

WINDOW

stdscr是WINDOW的一个特例,是默认存在的,除此之外,在WINDOW中可以使用newwin和delwin来创建和销毁窗口,具体函数如下

WINDOW *newwin(int num_of_lines,int num_of_cols,int start_y,int start_x);
//创建一个新窗口,行数列数和开始位置
//新窗口完全独立于已存在窗口,并且覆盖它们的内容
int delwin(WINDOW *window_to_delete);
//删除,不能删除stdscr和curscr

常用函数

先前已经使用过一些屏幕上的函数,例如addch、printw等,但是这些函数还可以加上一些前缀变成通用函数,前缀w用于窗口,mv用于光标移动,mvw用于在窗口中移动光标,需要注意的是,当加上了对应的前缀时,函数的参数也会发生对应的变化,下面给出一些加上前缀后的具体函数

int mvwaddch(WINDOW* window_pointer, int y, int x, const chtype char);
int mvwprint(WINDOW *window_pointer, int y, int x, const chtype char);
int mvwin(WINDOW *window_to_move, int new_y, int new_x, int new_x);
int touchwin(WINDOW *window_ptr);
//通知curses窗口内容已改变,下次刷新必须重新绘制
int scrollok(WINDOW *window_ptr, bool scroll_flag);
//控制卷屏,传递给函数是布尔值则允许卷
int scroll(WINDOW *window_ptr);
//窗口内容上卷一行

书上给出的一个运行的例子,代码和部分运行结果如下

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <curses.h>
int main()
{
    WINDOW *nw_ptr,*pw_ptr;//新窗口和弹出创刊
    char ch='a';
    initscr();//开模式
    move(5,5);//移动光标
    printw("%s","Multiple windows");
    refresh();
    for(int i=0;i<255;i++)
        for(int j=0;j<255;j++)
            {
                mvwaddch(stdscr,i,j,ch);//把数据插入整个屏幕
                ch=(++ch-'a')%26+'a';//循环小写字母
            }
    refresh();
    sleep(2);

    nw_ptr=newwin(10,20,5,5);//新窗口
    mvwprintw(nw_ptr,2,2,"%s","Hello World");
    mvwprintw(nw_ptr,5,2,"%s","1111111111111111111111111111111111111");
    wrefresh(nw_ptr);//刷新以显示
    sleep(2);

    ch='0';
    for(int i=0;i<255;i++)
        for(int j=0;j<255;j++)
        {
            mvwaddch(stdscr,i,j,ch);
            ch=(++ch-'0')%10+'0';//循环数字
        }
    refresh();
    sleep(2);
    
    touchwin(nw_ptr);//通知curses窗口内容已变,调用刷新要重写窗口
    wrefresh(nw_ptr);
    sleep(2);

    pw_ptr=newwin(10,20,8,8);//创建新窗口
    box(pw_ptr,'|','-');//加上框
    mvwprintw(pw_ptr,5,2,"%s","Pop up Window!");
    wrefresh(pw_ptr);
    sleep(2);

    touchwin(nw_ptr);//显示
    wrefresh(nw_ptr);
    sleep(2);
    wclear(nw_ptr);//清屏
    wrefresh(nw_ptr);
    sleep(2);
    delwin(nw_ptr);
    touchwin(pw_ptr);
    wrefresh(pw_ptr);
    sleep(2);
    delwin(pw_ptr);
    touchwin(stdscr);
    refresh();
    sleep(2);
    endwin();

    return 0;
}

运行的时候可以看到,创建的新窗口覆盖了原有的背景窗口不分,然后新的两个窗口彼此相互覆盖,需要注意的是,如果要用curses刷新多个窗口,只能人为的管理这些窗口之间的先后关系

在这里插入图片描述

屏幕刷新优化

对屏幕的优化刷新需要一定技巧,当要更新的终端是通过慢速链路连接到主机时,就可能因为设备之间的不同步出问题,在慢速链路上,屏幕绘制的速度会非常慢,curses提供了相对应的手段,具体如下

int wnoutrefresh(WINDOW *window_ptr);
//决定把哪些字符发到屏幕上,但是只是缓存
int doupdate(void);
//把最后的更新结果输出到屏幕上
//如果想重新绘制多个窗口,可以为每个窗口调用wnoutrefresh,然后最后调用doupdate即可
//这是利用了缓存的思路

子窗口

子窗口和窗口的关系有点类似父进程和子进程,它的创建和删除的相关函数如下

WINDOW *subwin(WINDOW *parent, int num_of_lines,int num_of_cols, int start_y, int start_x);  
//类似newwin,子窗口和父窗口共享同一字符存储空间
int delwin(WINDOW *window_to_delete);

子窗口最主要的用途是,提供一种简洁方式卷动另一窗口的部分内容,在使用子窗口的时候,刷新屏幕必须先对父窗口调用touchwin,下面是书上给的一个例子代码和运行结果

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#include <stdio.h>

int main()
{
    WINDOW *sub;//窗口指针
    char ch='1';
    initscr();
    for(int i=0;i<255;i++)
        for(int j=0;j<255;j++)
        {
            mvwaddch(stdscr,i,j,ch);//在对应位置插入字符
            ch=(++ch-'0')%9+'1';
        }

    sub=subwin(stdscr,10,20,10,10);//创建子窗口
    scrollok(sub,1);
    touchwin(stdscr);//刷新屏幕前调用父窗口
    refresh();
    sleep(1);

    werase(sub);//删除父窗口的对应区域
    mvwprintw(sub,2,0,"%s","scrolling");//输出
    wrefresh(sub);//刷新窗口
    sleep(1);

    for(int i=1;i<10;i++)//重新输出并滚动
    {
        wprintw(sub,"%s","wapping and scrolling");
        wrefresh(sub);
        sleep(1);
    }

    delwin(sub);
    touchwin(stdscr);
    refresh();
    sleep(1);

    endwin();

    
    return 0;
}

可以看到父窗口的一个小区域被清空,然后生成了一个子窗口,对子窗口进行输出并滚动

在这里插入图片描述

keypad

对于键盘上的按键,并不是所有的都可以通过ascall码来表示,比如insert、delete等,这些键在实际输入的时候往往是以escape字符开头的字符串序列,但这样就出现一个问题,系统需要识别单独按下escape键和以该键为首的字符串序列,curses提供了区分它们的实现,curses在启动时会关闭转义序列与逻辑键间的转换功能,通过keypad实现

int keypad(WINDOW *window_ptr, bool keypad_on);
//为了区分不同,curses会在检测到escape之后等待一小段时间,特别是启用keypad后

书上给出了一个keypad的实例,下面是代码和运行结果

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>
#include <string.h>
#include <ctype.h>
int main()
{
    initscr();
    crmode();
    keypad(stdscr,1);//启用keypad模式
    noecho();//不回显
    clear();
    mvprintw(5,5,"q to quit");//打印字符
    move(7,5);//移动光标
    refresh();
    int key=getch();
    while(key!=ERR&&key!='q')
    {
        move(7,5);
        clrtoeol();//清除当前位置到行尾
        if(isalpha(key))//如果是字符
            printw("Key was %c", key);
        else
        {
            switch(key)//用特殊的宏来判断
            {
                case 27: printw("%s","Escape key");break;
                case KEY_END: printw("%s","END key");break;
                case KEY_BEG: printw("%s","BEGINNING key");break;
                case KEY_RIGHT: printw("%s","RIGHT key");break;
                case KEY_LEFT: printw("%s", "LEFT key");break;
                case KEY_UP: printw("%s","UP key");break;
                case KEY_DOWN: printw("%s","DOWN key");break;
                default: printw("Unmatched - %d",key);break;
            }
        }
        refresh();
        key=getch();

    }
    endwin();
    return 0;
}

可以看到程序可以识别所有的字符,以及一些设定好的特殊按键

在这里插入图片描述

彩色显示

curses对颜色的支持是通过组合来实现的,对于每个想使用的颜色组合,用户必须同时定义一个字符的前景和背景,相关函数具体如下

bool has_colors(void);
//判断终端是否支持彩色显示
int start_color(void);
//初始化颜色显示
int init_pair(short pair_number, short foreground, short background);
//初始化一个颜色组合,用pair_number来替代
int COLOR_PAIR(int pair_number);
//把颜色组合作为属性返回
int pair_content(short pair_number, short *foreground, short *background);
//获得已定义的颜色组合信息
int init_color(short color_number, short red, short green, short blue);
//把一个已有的颜色重新定义

书上给出的例子和运行结果如下

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <curses.h>
int main()
{
    initscr();
    if(!has_colors())
    {
        endwin();
        fprintf(stderr,"ERROR1\n");
        exit(1);
    }
    if(start_color()!=OK)
    {
        endwin();
        fprintf(stderr,"ERROR2\n");
        exit(2);
    }        
    clear();
    mvprintw(5,5,"Colors types: %d, Color pairs: %d",COLORS,COLOR_PAIRS);
    refresh();
    
    init_pair(1,COLOR_RED,COLOR_BLACK);//初始化几个组合
    init_pair(2,COLOR_RED,COLOR_GREEN);
    init_pair(3,COLOR_GREEN,COLOR_RED);

    for(int i=1;i<=3;i++)
    {
        attroff(A_BOLD);//关闭加粗
        attrset(COLOR_PAIR(i));//设置颜色组合
        mvprintw(5+i,5,"COLOR pair %d", i);
        attrset(COLOR_PAIR(i)|A_BOLD);//设置颜色组合+加粗
        mvprintw(5+i,25,"Bold color pair %d", i);
        refresh();
        sleep(3);
    }
    endwin();
    return 0;
}

可以看到以不同的颜色组合和加粗显示了字符串

在这里插入图片描述

pad

有时在使用curses时需要先建立一个逻辑屏幕,然后再把其部分内容投射到物理屏幕上,这个逻辑屏幕的尺寸可能会大于实际屏幕,curses提供了一个数据结构pad,它可以控制尺寸大于正常窗口的逻辑屏幕,具体函数如下

WINDOW *newpad(int number_of_lines, int number_of_columns);
int prefresh(WINDOW *pad_ptr, int pad_row, int pad_column,
int screen_row_min, int screen_col_min, int screen_row_max, int screen_col_max);
//将pad从指定坐标开始的区域写到屏幕上指定的显示区域,后两个坐标是显示范围

书上给出的例子和运行结果如下

#include <unistd.h>
#include <stdlib.h>
#include <curses.h>

int main()
{
    WINDOW*pad;
    initscr();
    int lines=LINES+50,cols=COLS+50;
    pad=newpad(lines,cols);//创建新pad
    char ch='a';

    for(int i=0;i<lines;i++)
        for(int j=0;j<cols;j++)
        {
            mvwaddch(pad,i,j,ch);
            ch=(++ch-'a')%26+'a';
        }

    prefresh(pad,5,7,2,2,9,9);//刷新显示
    sleep(1);
    prefresh(pad,LINES+5,COLS+7,5,5,21,19);//移动,再刷新显示一遍
    sleep(1);
    delwin(pad);
    endwin();
    return 0;
}

在这里插入图片描述

总结

可以看到,linux通过curses实现了对屏幕、键盘的读取,以及对子窗口,pad等的调用,为C语言实现可交互的应用程序提供了很好的实现方法和思路

参考文献

  1. 《Linux程序设计(第四版)》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2193223.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【重学 MySQL】五十八、文本字符串(包括 enum set)类型

【重学 MySQL】五十八、文本字符串&#xff08;包括 enum set&#xff09;类型 CHAR 和 VARCHARTEXT 系列ENUMSET示例注意事项 在 MySQL 中&#xff0c;文本字符串类型用于存储字符数据。这些类型包括 CHAR、VARCHAR、TEXT 系列&#xff08;如 TINYTEXT、TEXT、MEDIUMTEXT 和 L…

鸿蒙开发(NEXT/API 12)【管理应用与Wear Engine服务的连接状态】手机侧应用开发

监测应用与Wear Engine服务的连接状态 华为运动健康App在后台停止服务&#xff08;如功耗过高&#xff09;&#xff0c;从而导致应用与Wear Engine服务的连接状态发生变化。对于类似这种不确定的断开情况&#xff0c;开发者可以通过本功能特性了解当前应用和Wear Engine的连接…

NatGo我的世界联机篇

书接上回 这里的TCP是JAVA&#xff0c;UDP是BE&#xff0c;选自适合你的映射类型 内网端口就填下面图片在你游戏同一个地方的数字!!! 就是我填12345的地方&#xff0c;mod-自定义局域网联机 默认 25565&#xff0c;如果出现无法创建本地游戏&#xff0c;那可能是端口被占用或…

卷积层是如何学习到图像特征的?

你好啊&#xff0c;我是董董灿。 想搞懂这个问题&#xff0c;需要先了解我们所说的特征指的是什么&#xff1f;然后再了解卷积核是如何学到的特征。 我们一步步来。 1、我们先来理解图像的特征 对于一张原始图像而言&#xff0c;说原始图像是相对于经过卷积处理而言的。 对…

【文心智能体】旅游攻略版,手把手教你调用插件实现智能体,绝对的干货满满!

1.灵感来源 需要创建一个智能体&#xff0c;首先当然是需要一个创作灵感啦&#xff0c;那么恰逢国庆假期&#xff0c;但是网上各种各样的旅游资料使我头晕目眩&#xff0c;刚好呢百度的文心智能体平台给我们提供了各种各样的插件以及知识库&#xff0c;可以供我们随心所欲地调…

嵌入式硬件设计中EDA布局与布线实现

大家好,今天主要给大家分享一下,如何使用立创EDA进行布局和布线,具体实现过程如下: 第一:PCB概念介绍 在介绍PCB的时候,先来说明一下,电子管的发明史。 贝尔在1876年发明了电话,爱迪生1879年发明了白炽灯、特斯拉于1888年发明了电动机,所有这些,都为电子学的诞生准…

2024 热门的4大电脑剪辑软件大盘点。

在电脑上进行视频剪辑能够让我们更好的发挥创意&#xff0c;制作出精彩的视频作品。同时也需要依赖一些比较专业的视频剪辑工具。这几款视频剪辑软件&#xff0c;无论是制作个人视频、商业广告还是电影预告片&#xff0c;都是非常不错的选择。 1、福昕电脑剪辑 直达链接&#…

vSAN05:vSAN延伸集群简介与创建、资源要求与计算、高级功能配置、维护、故障处理

目录 vSAN延伸集群延伸集群创建延伸集群的建议网络配置vSAN延伸集群的端口见证主机的资源要求vSAN延伸集群中见证节点带宽占用vSAN延伸集群的允许故障数vSAN延伸集群不同配置下的空间占用 vSAN延伸集群的HA配置vSAN延伸集群的DRS配置vSAN存储策略以及虚拟机/主机策略的互操作vS…

系统架构设计师③:数据块系统

系统架构设计师③&#xff1a;数据块系统 数据库模式 数据库模式是指数据库的结构和组织方式&#xff0c;它描述了数据库中数据的逻辑结构和组织方式&#xff0c;是数据库设计的核心组成部分。以下是关于数据库模式的详细解析&#xff1a; 一、定义与组成 定义&#xff1a;…

4款专业电脑数据恢复软件,帮你保障数据安全。

电脑里面会出现的数据丢失场景有很多&#xff0c;像硬盘故障、回收站清空、电脑格式化、系统崩溃、病毒入侵等等&#xff1b;如果发现数据丢失后&#xff0c;建议应停止使用电脑&#xff0c;避免新的数据写入覆盖丢失的数据。然后再尝试进行数据找回&#xff0c;如果想自己进行…

系统分析师16:系统测试与维护

1 内容概要 2 软件测试类型 2.1 测试类型 动态测试【计算机运行】 白盒测试法&#xff1a;关注内部结构与逻辑灰盒测试法&#xff1a;介于两者之间黑盒测试法&#xff1a;关注输入输出及功能 静态测试【人工监测和计算机辅助分析】 桌前检查代码审查代码走查以上三个都是做的…

【C++11】新特性

前言&#xff1a; C11 是C编程语言的一个重要版本&#xff0c;于2011年发布。它带来了数量可观的变化&#xff0c;包含约 140 个新特性&#xff0c;以及对 C03 标准中约600个缺陷的修正&#xff0c;更像是从 C98/03 中孕育出的新语言 列表初始化 C11 中的列表初始化&#xff0…

社群团购中的用户黏性价值:以开源小程序多商户AI智能名片商城源码为例

摘要&#xff1a;本文探讨社群团购中的用户黏性价值&#xff0c;分析其与传统团购网站的区别&#xff0c;并阐述开源小程序多商户AI智能名片商城源码在增强社群团购用户黏性方面可能发挥的作用。 一、引言 在当今的商业环境中&#xff0c;社群团购逐渐成为一种重要的营销模式。…

新个性化时尚解决方案!Prompt2Fashion:自动生成多风格、类型时尚图像数据集。

今天给大家介绍一种自动化生成时尚图像数据的方法Prompt2Fashion。 首先创建了一组描述&#xff0c;比如“适合婚礼的休闲风格服装”&#xff0c;然后用这些描述来指导计算机生成图像。具体来说&#xff0c;他们使用了大型语言模型来写出这些服装的描述&#xff0c;接着将这些描…

毕业设计 大数据电影数据分析与可视化系统

文章目录 0 简介1 课题背景2 效果实现3 爬虫及实现4 Flask框架5 Ajax技术6 Echarts7 最后 0 简介 今天学长向大家介绍一个机器视觉的毕设项目 &#x1f6a9;基于大数据的电影数据分析与可视化系统 项目运行效果(视频)&#xff1a; 毕业设计 大数据电影评论情感分析 &#x1…

运动传感器

运动传感器 当你走近一些自动开关门、自动开关灯泡或自动启动自动扶梯的地方时&#xff0c;你是否会产生这样的疑问&#xff1a;**"它是怎么做到的&#xff1f; **它是怎么做到的&#xff1f; 如果有&#xff0c;本教程不仅会回答&#xff0c;还会告诉你如何制作。 让我们…

【Redis】Hash类型的常用命令

背景&#xff1a;redis中存储数据采取key-value键值对的形式&#xff0c;而hash内部也是键值对&#xff0c;为了区别这两个东西&#xff0c;hash内部的键值对称为&#xff1a;field-value&#xff0c;而redis的为key-value&#xff0c;这里的value包括&#xff1a;field-value。…

基于pytorch的手写数字识别

import pandas as pd import numpy as np import torch import matplotlib import matplotlib.pyplot as plt from torch.utils.data import TensorDataset, DataLoadermatplotlib.use(tkAgg)# 设置图形配置 config {"font.family": serif,"mathtext.fontset&q…

如何在华为云服务器查看IP地址,及修改服务器登录密码!!!

1.在华为云服务器查看IP地址 (1).第一步&#xff1a; 先找到控制台 (2).第二步&#xff1a; 点击华为云Flexus云服务 (3)第三步&#xff1a; 找到公网IP&#xff0c;就找到华为云服务器IP地址啦。 注意&#xff1a;在操作以上步骤的前提是要已注册华为云账号及购买云服务器…