RT-Thread 学习笔记(十四)--- 开启基于RTGUI的LCD显示功能(4)<demo组件的按键响应和焦点支持>

news2024/11/24 4:09:48

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2

硬件环境:Armfly STM32F103ZE-EK v3.0开发板

参考文章:RT-Thread编程指南

RT-Thread_1.2.0+lwip+rtgui0.8.0 移植心得

RT-Thread RTOS组件:RTGUI教程 Hello World

前面基本解决了触摸屏的驱动和校正问题,但是还有些问题,比如按键响应,触摸屏校正数据的存储,打开多个Demo组件时会有问题存在等,接下来就要研究这些问题。

【1】按键响应

(1)查看原理图硬件接口电路,如下图:

从原理图可以看到,一个五向摇杆有五个按键,已经能够满足LCD显示屏上操作的需要。可以根据原理图上的标出的硬件接口修改RTGUI底层硬件接口代码。

(2)对于RT-Thread来讲,对于底层硬件,需要将按键信息包装成事件信息传递个GUI server处理,然后server发给LCD 作为响应。所以需要新建一个文件key.c,处做这件事情。参考realtouch和魔笛F1开发板的按键例程代码修改而得到key.c的代码如下:

<pre name="code" class="cpp">#include <rtthread.h>
#include <board.h>

#include <rtgui/event.h>
#include <rtgui/rtgui_server.h>

//常规按键处理使用
#define DEBOUNCE_SHORT_TIME 	3   // 轻触按键消抖时间5(单位:20毫秒)
#define DEBOUNCE_LONG_TIME  	5  	// 长按键时间DEBOUNCE_COUT_FIRST+DEBOUNCE_COUT_INTERVAL*DEBOUNCE_LONG_TIME(单位:10毫秒)
#define DEBOUNCE_COUT_FIRST 	500//50 // 连按键间隔时间100(单位:20毫秒)
#define DEBOUNCE_COUT_INTERVAL 	10  // 连按键间隔时间50(单位:20毫秒)

//特殊按键处理使用
#define C_RELASE_COUT			3
#define C_SHORT_COUT			3		//3*20ms
#define C_SPECIAL_LONG_COUT		60  //60*20ms

//按键标志
#define C_FLAG_SHORT			0x00000001
#define C_FLAG_COUNT			0x00000002
#define C_FLAG_LONG				0x00000004
#define C_FLAG_RELASE			0x00000008

//按键键值
#define  C_UP_KEY 				0x01
#define  C_DOWN_KEY 			0x02
#define  C_LEFT_KEY 			0x04
#define  C_RIGHT_KEY 			0x08
#define  C_ENTER_KEY 			0x10
#define  C_SPECIAL_KEY 		C_ENTER_KEY

/*enter键长按 我们定义为home键*/
#define  C_HOME_KEY 			C_SPECIAL_KEY+0x44

/*
KEY_UP    PG15
KEY_DOWN  PD3
KEY_LEFT  PG14
KEY_RIGHT PG13
KEY_ENTER PG7
*/

#define KEY_UP_GETVALUE()     GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_15)//PG15
#define KEY_DOWN_GETVALUE()   GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_3)//PD3
#define KEY_LEFT_GETVALUE()   GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_14)//PG14
#define KEY_RIGHT_GETVALUE()  GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_13)//PG13
#define KEY_ENTER_GETVALUE()  GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_7)//PG7

/* 使用面向对象的方式,将按键所用到的所有元素进行打包 */
struct rtgui_key
{
    rt_timer_t poll_timer;
    struct rtgui_event_kbd kbd_event;

    rt_uint32_t key_last;
    rt_uint32_t key_current;
    //检测到的按键值
    rt_uint32_t key_get;
    //常规按键使用
    rt_uint32_t key_debounce_count;
    rt_uint32_t key_long_count;
    //特殊按键使用
    rt_uint32_t key_special_count;
    rt_uint32_t key_relase_count;
    //按键标志
    rt_uint32_t key_flag;

};

static struct rtgui_key *key;


static void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG|RCC_APB2Periph_GPIOD,ENABLE);

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Pin   = (GPIO_Pin_15|GPIO_Pin_14|GPIO_Pin_13|GPIO_Pin_7);
    GPIO_Init(GPIOG, &GPIO_InitStructure);
	
    GPIO_InitStructure.GPIO_Pin   = (GPIO_Pin_3);
    GPIO_Init(GPIOD, &GPIO_InitStructure);

}


static void key_timeout(void* parameter)
{
		//按键未按下时,每位读入的值为1
    key->key_current = KEY_UP_GETVALUE();
    key->key_current |= KEY_DOWN_GETVALUE()<<1;
    key->key_current |= KEY_LEFT_GETVALUE()<<2;
    key->key_current |= KEY_RIGHT_GETVALUE()<<3;
    key->key_current |= KEY_ENTER_GETVALUE()<<4;

    key->key_current =~ (key->key_current);//取反
    key->key_current &= 0x0000001f; //过滤掉低五位以外的值,因为只有五个按键


    key->key_flag &= ~C_FLAG_SHORT;
    key->key_flag &= ~C_FLAG_COUNT;
    key->key_flag &= ~C_FLAG_LONG;
    key->key_get = 0;

//
    /*对于有长按和短按的特殊键做处理*/
    if ((key->key_flag)&C_FLAG_RELASE)
    {   //检查放键
        if (key->key_current == 0)
        {
            if ((++(key->key_relase_count)) >= C_RELASE_COUT)
            {   //按键已经放开
                key->key_relase_count = 0;
                key->key_flag &= ~C_FLAG_RELASE;
            }
        }
        else
        {
            key->key_relase_count = 0;
        }
    }
    else
    {   //检查按键
        if (key->key_current == C_SPECIAL_KEY)
        {
            if ((++(key->key_special_count)) >= C_SPECIAL_LONG_COUT)
            {
                key->key_special_count = 0;

                key->key_get = C_HOME_KEY;
                key->key_flag |= C_FLAG_LONG;		//特殊键 长按键按下
                key->key_flag |= C_FLAG_RELASE;	//按下后要求检测放键
            }
        }
        else
        {   //放开键后才检测短按
            if ((key->key_special_count >= C_SHORT_COUT) && (key->key_special_count <C_SHORT_COUT+30))
            {
                key->key_get = C_SPECIAL_KEY;
                key->key_flag |= C_FLAG_SHORT;	//特殊键 短按键按下
            }
            key->key_special_count = 0;
        }
    }

// 普通按键处理
    if((key->key_current == 0)||(key->key_current != key->key_last)|| (key->key_current == C_SPECIAL_KEY))
    {
        key->key_debounce_count = 0;			//第一次
        key->key_long_count = 0;	        //清除长按键计数器
    }
    else
    {
        if(++(key->key_debounce_count) == DEBOUNCE_SHORT_TIME)
        {
            key->key_get = key->key_current;
            key->key_flag |= C_FLAG_SHORT;	//短按键按下
        }
        if(key->key_debounce_count == DEBOUNCE_COUT_FIRST + DEBOUNCE_COUT_INTERVAL)
        {
            key->key_get = key->key_current;
            key->key_flag |= C_FLAG_COUNT;	//连按键 按键按下
            key->key_debounce_count = DEBOUNCE_COUT_FIRST;
            ++(key->key_long_count);
        }

        if(key->key_long_count == DEBOUNCE_LONG_TIME)
        {
            key->key_get = key->key_current;
            key->key_flag |= C_FLAG_LONG;	//短按键按下
            key->key_long_count=DEBOUNCE_LONG_TIME+1;
        }
    }

    key->key_last = key->key_current;				// 保存本次键值


    /* 检测到按键后,向系统上报键值 */
    key->kbd_event.key = RTGUIK_UNKNOWN;
    key->kbd_event.type = RTGUI_KEYDOWN;

    if (key->key_get)
    {
        rt_kprintf("key = %x \n",key->key_get);
        if (((key->key_get)==C_UP_KEY) && ((key->key_flag) & C_FLAG_SHORT))
            key->kbd_event.key  = RTGUIK_UP;

        if (((key->key_get)==C_DOWN_KEY) && ((key->key_flag) & C_FLAG_SHORT))
            key->kbd_event.key  = RTGUIK_DOWN;

        if (((key->key_get)==C_LEFT_KEY) && ((key->key_flag) & C_FLAG_SHORT))
            key->kbd_event.key  = RTGUIK_LEFT;

        if (((key->key_get)==C_RIGHT_KEY) && ((key->key_flag) & C_FLAG_SHORT))
            key->kbd_event.key  = RTGUIK_RIGHT;

        //if (((key->key_get)==C_STOP_KEY) && ((key->key_flag) & C_FLAG_SHORT))
        //	key->kbd_event.key  = RTGUIK_UP;
        //if (((key->key_get)==C_MENU_KEY) && ((key->key_flag) & C_FLAG_SHORT))
        //	key->kbd_event.key  = RTGUIK_UP;
        if ((key->key_get)==C_ENTER_KEY)
            key->kbd_event.key  = RTGUIK_RETURN;

        if ((key->key_get)==C_HOME_KEY)
            key->kbd_event.key  = RTGUIK_HOME;
    }

    if (key->kbd_event.key != RTGUIK_UNKNOWN)
    {
        /* 先上报按键按下*/
        rtgui_server_post_event(&(key->kbd_event.parent), sizeof(key->kbd_event));

        /* delay to post up event */
        rt_thread_delay(2);

        /* 再上报按键松开,完成一个从按下到松开的组合*/
        key->kbd_event.type = RTGUI_KEYUP;
        rtgui_server_post_event(&(key->kbd_event.parent), sizeof(key->kbd_event));
    }
}



int rt_hw_key_init(void)
{
    GPIO_Configuration();

    key = (struct rtgui_key*)rt_malloc (sizeof(struct rtgui_key));
    if (key == RT_NULL)
        return -1; /* no memory yet */

    /* init keyboard event */
    RTGUI_EVENT_KBD_INIT(&(key->kbd_event));
    key->kbd_event.wid = RT_NULL;
    key->kbd_event.mod  = RTGUI_KMOD_NONE;
    key->kbd_event.unicode = 0;

    key->key_last = 0;
    key->key_current = 0;
    key->key_get = 0;
    key->key_debounce_count = 0;
    key->key_long_count = 0;
    key->key_special_count = 0;
    key->key_relase_count = 0;
    key->key_flag = 0;

    /* create 1/50=20ms  timer */
    key->poll_timer = rt_timer_create("key", key_timeout, RT_NULL,
                                      RT_TICK_PER_SECOND/50, RT_TIMER_FLAG_PERIODIC);

    /* 启动定时器 */
    if (key->poll_timer != RT_NULL)
        rt_timer_start(key->poll_timer);

    return 0;
}

INIT_DEVICE_EXPORT(rt_hw_key_init);

 

需要说明的是,key.c是启用了五向摇杆的五个按键,而在demo_application.c中,使用了RTGUIK_LEFT和RTGUI_RIGHT两个方向的按键,代码如下:

static rt_bool_t demo_handle_key(struct rtgui_object *object, struct rtgui_event *event)
{
    struct rtgui_event_kbd *ekbd = (struct rtgui_event_kbd *)event;

    if (ekbd->type == RTGUI_KEYUP)
    {
        if (ekbd->key == RTGUIK_RIGHT)
        {
            demo_view_next(RT_NULL, RT_NULL);
            return RT_TRUE;
        }
        else if (ekbd->key == RTGUIK_LEFT)
        {
            demo_view_prev(RT_NULL, RT_NULL);
            return RT_TRUE;
        }
    }
    return RT_TRUE;
}

(3)把key.c添加到drivers目录下以后,还需要修改下drivers目录下Sconscript脚本,打开脚本文件定位到30行附近,加入如下代码:

# add RTGUI drvers.
if GetDepend('RT_USING_RTGUI'):
    src += ['key.c']
    if rtconfig.RT_USING_LCD_TYPE == 'ILI932X' :
        src += ['ili_lcd_general.c']
    elif rtconfig.RT_USING_LCD_TYPE == 'SSD1289':
        src += ['ssd1289.c']
    elif rtconfig.RT_USING_LCD_TYPE == 'OTM4001A':
        src += ['otm4001a.c']

CPPPATH = [cwd]
别忘了,书写格式按四个空格或者tab键递进,否则会出现执行脚本时会出现错误。然后保存。

(4)在demo_application.c中先加入三个demo文件,代码如下:

/*    demo_view_benchmark();

    demo_view_dc();
#ifdef RTGUI_USING_TTF
    demo_view_ttf();
#endif

#ifndef RTGUI_USING_SMALL_SIZE
    demo_view_dc_buffer();
#endif
    demo_view_animation();
#ifndef RTGUI_USING_SMALL_SIZE
    demo_view_buffer_animation();
    demo_view_instrument_panel();
#endif
    demo_view_window();
*/    demo_view_label();
    demo_view_button();
    demo_view_checkbox();
/*    demo_view_progressbar();
    demo_view_scrollbar();
    demo_view_radiobox();
    demo_view_textbox();
    demo_view_listbox();
    demo_view_menu();
    demo_view_listctrl();
    demo_view_combobox();
    demo_view_slider();
    demo_view_notebook();
    demo_view_mywidget();
    demo_plot();
	demo_view_digtube();
*/

然后保存并scons编译,下载,复位后,五向摇杆向右摇下,会切换到下一个页面,向左摇下,会切换到上一个页面,因为我们的demo页面还没打开完,左右按两下是可以看到效果的。

【2】屏幕中文支持

(1)在rtconfig.h文件中打开RTGUI_USING_FONTHZ向关编译选项,定位到179行附近,代码修改如下:

#define RTGUI_USING_FONT16
/* support Chinese font */
#define RTGUI_USING_FONTHZ
/* use DFS as file interface */
#define RTGUI_USING_DFS_FILERW
/* use font file as Chinese font */
#define RTGUI_USING_HZ_FILE
/* use Chinese bitmap font */
#define RTGUI_USING_HZ_BMP
/* use small size in RTGUI */
#define RTGUI_USING_SMALL_SIZE

(2)修改rtgui_system_server_init()的初始化调用

如果按默认调用,RTGUI在打开上面的RTGUI_USING_FONTHZ选项后,显示中文时会出现乱码。

<1>打开rtgui/common/rtgui_system.c文件,定位到58行附近,注释掉组件加载的宏,代码修改如下:

int rtgui_system_server_init(void)
{
    rt_mutex_init(&_screen_lock, "screen", RT_IPC_FLAG_FIFO);

    /* the graphic device driver must be set before initialization */
    RT_ASSERT(rtgui_graphic_driver_get_default() != RT_NULL);

    /* init image */
    rtgui_system_image_init();
    /* init font */
    rtgui_font_system_init();

    /* set the rect of main window to full screen */
    rtgui_graphic_driver_get_rect(rtgui_graphic_driver_get_default(), &_mainwin_rect);

    /* init rtgui server */
    rtgui_topwin_init();
    rtgui_server_init();

	/* use driver rect for main window */
	rtgui_graphic_driver_get_rect(rtgui_graphic_driver_get_default(), &_mainwin_rect);

    /* init theme */
    rtgui_system_theme_init();
    return 0;
}
//INIT_APP_EXPORT(rtgui_system_server_init);


<2>在application.c的RTGUI初始化部分加入rtgui_system_server_init()调用,定位到83行附近,确认代码修改和下面一致:

void rt_init_thread_entry(void* parameter)
{
	
		/* initialization RT-Thread Components */
		rt_components_init();
		
#if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT)
		/* mount SPI flash as root directory */ 
    if (dfs_mount("flash0", "/", "elm", 0, 0) == 0)
    {      
				rt_kprintf("flash0 mount to /.\n");				
    }
    else
        rt_kprintf("flash0 mount to / failed.\n");
		/* mount SD Card as /dev/sd directory */ 
    if (dfs_mount("sd0", "/dev", "elm", 0, 0) == 0)
    {
        rt_kprintf("sd0 mount to /dev.\n");
    }
    else		
        rt_kprintf("sd0 mount to /dev failed.\n");	
#endif /* RT_USING_DFS */		
				       
#ifdef RT_USING_RTGUI
		{
				rt_device_t lcd; 	
				/* find lcd device */
				lcd = rt_device_find("lcd");
				/* set lcd device as rtgui graphic driver */
				rtgui_graphic_set_device(lcd);
				rtgui_system_server_init();
				gui_application_init();
#ifdef RTGUI_USING_CALIBRATION
				calibration_set_restore(calibration_restore);//initialize the pointer to load user data
				calibration_set_after(calibration_store); //initialize the poiter to save user data
				calibration_init();		
#endif /* RTGUI_USING_CALIBRATION */	
		}
#endif /* RT_USING_RTGUI */

需要强调下,rt_components_init()需要在开始部分调用,因为硬件初始化都是在这个函数中进行的。

(3)确认各硬件初始化代码是否加入了组件调用导入的宏INIT_DEVICE_EXPORT(xxx_xxx_init);

<1>otm4001a.c文件的int rt_hw_lcd_init(void)的后面,代码如下:

int rt_hw_lcd_init(void)
{
	
	/* register lcd device */
	_lcd_device.type  = RT_Device_Class_Graphic;
	_lcd_device.init  = lcd_init;
	_lcd_device.open  = lcd_open;
	_lcd_device.close = lcd_close;
	_lcd_device.control = lcd_control;
	_lcd_device.read  = RT_NULL;
	_lcd_device.write = RT_NULL;

	_lcd_device.user_data = &otm4001_ops;
    
  otm4001_hw_init();

	lcd_set_backlight(200);
    /* register graphic device driver */
	rt_device_register(&_lcd_device, "lcd",
	RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
	return 0;
}
INIT_DEVICE_EXPORT(rt_hw_lcd_init);

<2>touch_driver.c的468行附近在int rtgui_touch_hw_init(void)的末尾处,代码如下:

    /* register touch device to RT-Thread */
    rt_device_register(&(touch->parent), "touch", RT_DEVICE_FLAG_RDWR);
		return 0;
}
INIT_DEVICE_EXPORT(rtgui_touch_hw_init);

<3>在key.c文件的262行附近的int rt_hw_key_init(void)的末尾处,代码如下:

    /* startup the timer */
    if (key->poll_timer != RT_NULL)
        rt_timer_start(key->poll_timer);

    return 0;
}
INIT_DEVICE_EXPORT(rt_hw_key_init);

(4)加载汉字库,可参考下面步骤进行,如果文件系统已经挂载,下面步骤2的前面两步可不必进行。

1. 准备资源文件:
把sdcard目录下所有目录复制到SD卡根目录,
然后把SD卡插到开发板上面备用。
2. finsh执行:
2.1 格式化flash,然后重新启动。
finsh>>mkfs("elm", "flash0")
2.2 创建目录用于挂载SD卡及资源文件目录,因需要挂载SD卡,所以最后需要重新启动。
finsh>>mkdir("/dev")
finsh>>mkdir("/resource")
2.3 准备就绪后,启动会显示根目录和SD卡都挂载成功,然后就可以开始复制资源文件了。
finsh>>copy("/dev/resource/gbk2uni.tbl", "/resource/gbk2uni.tbl")
finsh>>copy("/dev/resource/uni2gbk.tbl", "/resource/uni2gbk.tbl")
finsh>>copy("/dev/resource/hzk12.fnt", "/resource/hzk12.fnt")
finsh>>copy("/dev/resource/hzk16.fnt", "/resource/hzk16.fnt")
2.4 所有资源文件复制完成后,重启动即可
(5)如果上面修改完成并保存了,执行scons编译,下载的开发板上后可以看到之前的乱码变成中文了。

【3】焦点支持

未完,待续。。。

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

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

相关文章

2022/12/26 请你谈谈数据库事务机制?

1 事务四大特征 一般来说&#xff0c;事务是必须满足4个条件&#xff08;ACID&#xff09;&#xff1a;原子性&#xff08;Atomicity&#xff09;、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;、持久性&#xff08;Durability&#…

软件测试工程职场发展细谈

前言 今天几个测试圈子的大佬约了饭局&#xff0c;席间彼此交流了很多关于职场工作上测试相关的话题&#xff0c;听了他们的一些观点很有启发&#xff0c;我自己对于聊的话题也做了一些描述和实际的案例说明。下面是聊的一些关键话题&#xff0c;我将交流的内容和个人观点整理…

(二)JavaScript

JavaScript 是一门跨平台、面向对象的脚本语言。JavaScript 是用来控制网页行为的&#xff0c;它能使网页可交互。 一、JavaScript 引入方式&#xff08;P71&#xff09; &#xff08;1&#xff09;内部脚本&#xff1a;将JS代码定义在HTML页面中 &#xff08;2&#xff09;外部…

ActiveMQ集群模式

目录 一、面试题 二、多节点集群是什么 三、zookeeperreplicated-leveldb-store的主从集群 四、官网集群原理图 五、部署规划和步骤 六、集群可用性测试 一、面试题 引入消息队列之后该如何保证其高可用性 二、多节点集群是什么 基于ZooKeeper和LevelDB搭建ActiveMQ 集…

API签名鉴权设计

鉴权作用 在实际的业务中&#xff0c;必然会存在和其他平台系统进行数据传输。这个时候出于对数据的保密要求&#xff0c;都会对接口&#xff08;API&#xff09;添加鉴权机制&#xff0c;识别调用方的真实身份&#xff0c;对未通过鉴权的请求不做任何业务处理&#xff0c;以帮…

国科大模式识别导论作业3:神经网络

目录题目代码data.pyutils.pynetwork.pymain.py结果整理一下近期作业中的编程题&#xff0c;仅供交流学习题目 本题使用的数据如下&#xff1a; 第一类 10 个样本&#xff08;三维空间&#xff09;&#xff1a; [ 1.58, 2.32, -5.8], [ 0.67, 1.58, -4.78], [ 1.04, 1.01, -3…

OpenCV 图像旋转、平移、缩放

本文是 OpenCV图像视觉入门之路的第7篇文章&#xff0c;本文详细的进行了图像的缩放 cv2.resize()、旋转 cv2.flip()、平移 cv2.warpAffine()等操作。 OpenCV 图像旋转、平移、缩放目录 1 缩放图片 2 翻转图片 2.1 垂直翻转 2.2 水平翻转 2.3 水平垂直翻转 ​编辑 3 平移…

百度离线人脸识别SDK

1&#xff0c;采坑备忘 &#xff08;1&#xff09;8.1版本的SDK在spring-boot接口访问第一次正常&#xff0c;第二次之后JVM会奔溃&#xff0c;可能是java gc 处理C开出的内存有问题。 换6.1.3版本的SDK。 javaWindows百度离线人脸识别SDK6.1.3-Java文档类资源-CSDN下载javaW…

Harmony/OpenHarmony应用开发-转场动画页面间转场

在全局pageTransition方法内配置页面入场和页面退场时的自定义转场动效。 说明&#xff1a;从API Version 7开始支持。开发语言ets. 名称 参数 参数描述 PageTransitionEnter { type: RouteType, duration: number, curve: Curve | string, delay: number } 设置当前页面…

1998-2014年企业绿色发展数据库

1998-2014年工业企业的排放排污和环境治理等信息数据 1、时间&#xff1a;1998-2014年 2、数据来源&#xff1a;原环保部。 3、统计字段&#xff1a;主要有企业基本信息、生产信息、水环境、大气环境&#xff0c;内容涵盖了资源利用类指标&#xff08;工业用水量、煤炭消费量…

YGG 与 Thirdverse 达成合作,将《足球小将》IP 带入 Web3

YGG 与 Thirdverse 建立了合作关系&#xff0c;Thirdverse 是一家专注于多人 VR 和 Web3 游戏的游戏工作室&#xff0c;在日本和美国分别设有办事处。 YGG 通过购买未来股权的简单协议&#xff08;SAFE&#xff09;参与了 Thirdverse 近期的 1500 万美元融资。这种合作关系将使…

FastAPI从入门到实战(16)——依赖项

依赖注入是耳熟能详的一个词了&#xff0c;听起来很复杂&#xff0c;实际上并没那么复杂&#xff0c;正常的访问需要接受各种参数来构造一个对象&#xff0c;依赖注入就变成了只接收一个实例化对象&#xff0c;主要用于共享业务逻辑、共享数据库连接、实现安全、验证、权限等相…

原油投资怎么样赚钱?原油投资赚钱技巧有哪些?

以前没有交易过原油的投资者&#xff0c;看到其他投资者从中获得了较好的盈利&#xff0c;也想通过原油投资来赚钱。那么原油投资到底能不能赚钱&#xff0c;是很多新手投资者比较想了解的问题。其实原油投资想盈利并不能全部依靠运气&#xff0c;只有掌握了原油投资赚钱技巧&a…

【Java基础】Java日志—什么是日志级别?如何配置数据源到不同的位置?配置文件内容都是什么含义?

目录 一、log4j1详情&#xff1a;记录器和日志级别 二、 log4j1详情&#xff1a;输出源【输出到不同的位置】 1、ConsoleAppender【将日志输出到控制台】 2、FileAppender【将日志输出到文件】 3、DailyRollingFileAppender【每日输出到一个新文件】 4、JDBCAppender【输…

FineReport开源报表系统-JS实现切换Tab块时进行数据联动

1. 概述 1.1 预期效果 在决策报表中&#xff0c;希望 Tab 块轮播切换时&#xff0c;可实现与报表块的数据联动。如下图所示&#xff1a; 1.2 实现思路 通过 JS 获取每个 Tab 块的轮播标题&#xff0c;转换为参数值&#xff0c;再通过控件进行界面传参&#xff0c;实现联动效果…

程序员工作五年后一般会怎样?

最近看到一些吐血言论“一个程序员工作5年后还没成为大牛&#xff0c;是不是该考虑别的路子了&#xff1f;”还有“程序员入行五年&#xff0c;有可能攒够80吗&#xff1f;”不是&#xff0c;程序员工作五年&#xff0c;是戳中了谁的痛点吗&#xff1f;&#xff1f;大家对五年经…

128页4万字某智慧能源集团数字化管理平台项目建议书

【版权声明】本资料来源网络&#xff0c;仅用于行业知识分享&#xff0c;供个人学习参考&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间进行删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 方案设计 在当…

公司新来的软件测试工程师接私活被抓了,难怪他天天加班到凌晨

昨天和我一起进公司的测试部门同事上班接私活被老板抓了&#xff0c;这人才来不到两个月&#xff0c;每天加班到凌晨。刚开始还以为他是个卷王&#xff0c;没想到此人上班时间接单&#xff0c;用加班时间来完成公司需求&#xff0c;造成努力的假象。被老板在办公室骂了俩小时&a…

v$asm_disk中free_mb低于300m导致加盘报ora-15041

背景&#xff1a; 某项目扩容加盘到磁盘组中报磁盘组空间耗尽的错误&#xff0c;如下 明明是加盘&#xff0c;却报空间不足的错误&#xff0c;令人费解 报错的磁盘组为normal冗余&#xff0c;且Usable_file_MB为负&#xff0c;且Free_MB剩余很少或为0 问题排查&#xff1a; …

MS 训练笔记【2】:nnFormer

文章目录前言1. 安装2. 训练与测试2.1. 数据处理2.1.1. 整理数据路径2.1.2. 设置 nnFormer 读取文件的路径2.1.3. 数据集预处理2.2. 训练2.2.1. 训练代码2.2.2. 可能出现的问题及解决办法2.3. 预测总结前言 本文主要记载 nnFormer 从安装到训练再到推理的过程。nnFormer 的环境…