20210324

20210324

问题sigsegv

attribute
__attribute__((constructor)) static void _pk_extension_inject_entry(void) {

attribute

GNU C 的一大特色就是__attribute__ 机制。__attribute__ 可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute )。

__attribute__ 书写特征是:__attribute__ 前后都有两个下划线,并切后面会紧跟一对原括弧,括弧里面是相应的__attribute__ 参数。

语法格式

__attribute__((attribute-list))

案例分析

int main(int argc, char * argv[]) {
    @autoreleasepool {
        printf("main function");
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
__attribute__((constructor)) static void beforeFunction()
{
    printf("beforeFunction\n");
}
运行结果
beforeFunction
main function

所以这个__attribute__((constructor))应该是在main函数之前,执行一个函数,便于我们做一些准备工作.后来,查阅了GNU的文档,印证了我的想法.

另外在文档中,还有提及,还有这么一个写法__attribute__((destructor)).文档中关于这两个用法的说明如下:

The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () completes or exit () is called. Functions with these attributes are useful for initializing data that is used implicitly during the execution of the program.

大概意思是:

constructor参数让系统执行main()函数之前调用函数(被__attribute__((constructor))修饰的函数).同理, destructor让系统在main()函数退出或者调用了exit()之后,调用我们的函数.带有这些修饰属性的函数,对于我们初始化一些在程序中使用的数据非常有用.

带有优先级的参数

按照文档中所说,我们还可以给属性设置优先级.这些函数并不非要写到main.m文件中,无论写到哪里,结果都是一样的.但是,为了更显式的让阅读者看到这些定义,至少,还是在main.m文件中留个声明.

声明和实现分离的写法如下:

//声明
__attribute__((constructor(101))) void before1();

//实现
void before1()
{
    printf("before1\n");
}
static  __attribute__((constructor(101))) void before1()
{
    
    printf("before1\n");
}
static  __attribute__((constructor(102))) void before2()
{
    
    printf("before2\n");
}
static  __attribute__((constructor(102))) void before3()
{
    
    printf("before3\n");
}

上面的代码没有什么疑问.以上三个函数会依照优先级的顺序调用.另外,我以前看过,这个1-100的范围是保留的,所以,最好从100之后开始用.(但是实际上,我在项目中测试100以内的,也没有得到警告)

附上sigsegv获取栈帧信息代码

#ifndef _GNU_SOURCE
	#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <ucontext.h>


/* 纯C环境下,定义宏NO_CPP_DEMANGLE */
#if (!defined(__cplusplus)) && (!defined(NO_CPP_DEMANGLE))
# define NO_CPP_DEMANGLE
#endif

#ifndef NO_CPP_DEMANGLE
# include <cxxabi.h>
# ifdef __cplusplus
	using __cxxabiv1::__cxa_demangle;
# endif
#endif

#if (defined HAS_ULSLIB)
# include <uls/logger.h>
# define sigsegv_outp(x)	sigsegv_outp(, gx)
#else
# define sigsegv_outp(x, ...) 	fprintf(stderr, x"\n", ##__VA_ARGS__)
#endif

#if (defined (__x86_64__))
# define REGFORMAT   "%016lx"	
#elif (defined (__i386__))
# define REGFORMAT   "%08x"
#elif (defined (__arm__))
# define REGFORMAT   "%lx"
#endif

static void print_reg(const ucontext_t *uc) 
{
#if (defined (__x86_64__)) || (defined (__i386__))
	int i;
	for (i = 0; i < NGREG; i++) {
		sigsegv_outp("reg[%02d]: 0x"REGFORMAT, i, uc->uc_mcontext.gregs[i]);
	}
#elif (defined (__arm__))
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 0, uc->uc_mcontext.arm_r0);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 1, uc->uc_mcontext.arm_r1);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 2, uc->uc_mcontext.arm_r2);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 3, uc->uc_mcontext.arm_r3);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 4, uc->uc_mcontext.arm_r4);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 5, uc->uc_mcontext.arm_r5);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 6, uc->uc_mcontext.arm_r6);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 7, uc->uc_mcontext.arm_r7);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 8, uc->uc_mcontext.arm_r8);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 9, uc->uc_mcontext.arm_r9);
	sigsegv_outp("reg[%02d]		= 0x"REGFORMAT, 10, uc->uc_mcontext.arm_r10);
	sigsegv_outp("FP		= 0x"REGFORMAT, uc->uc_mcontext.arm_fp);
	sigsegv_outp("IP		= 0x"REGFORMAT, uc->uc_mcontext.arm_ip);
	sigsegv_outp("SP		= 0x"REGFORMAT, uc->uc_mcontext.arm_sp);
	sigsegv_outp("LR		= 0x"REGFORMAT, uc->uc_mcontext.arm_lr);
	sigsegv_outp("PC		= 0x"REGFORMAT, uc->uc_mcontext.arm_pc);
	sigsegv_outp("CPSR		= 0x"REGFORMAT, uc->uc_mcontext.arm_cpsr);
	sigsegv_outp("Fault Address	= 0x"REGFORMAT, uc->uc_mcontext.fault_address);
	sigsegv_outp("Trap no		= 0x"REGFORMAT, uc->uc_mcontext.trap_no);
	sigsegv_outp("Err Code	= 0x"REGFORMAT, uc->uc_mcontext.error_code);
	sigsegv_outp("Old Mask	= 0x"REGFORMAT, uc->uc_mcontext.oldmask);
#endif
}

static void print_call_link(const ucontext_t *uc) 
{
	int i = 0;
	Dl_info	dl_info;

#if (defined (__i386__))
	const void **frame_pointer = (const void **)uc->uc_mcontext.gregs[REG_EBP];
	const void *return_address = (const void *)uc->uc_mcontext.gregs[REG_EIP];
#elif (defined (__x86_64__))
	const void **frame_pointer = (const void **)uc->uc_mcontext.gregs[REG_RBP];
	const void *return_address = (const void *)uc->uc_mcontext.gregs[REG_RIP];
#elif (defined (__arm__))
/* sigcontext_t on ARM:
        unsigned long trap_no;
        unsigned long error_code;
        unsigned long oldmask;
        unsigned long arm_r0;
        ...
        unsigned long arm_r10;
        unsigned long arm_fp;
        unsigned long arm_ip;
        unsigned long arm_sp;
        unsigned long arm_lr;
        unsigned long arm_pc;
        unsigned long arm_cpsr;
        unsigned long fault_address;
*/
	const void **frame_pointer = (const void **)uc->uc_mcontext.arm_fp;
	const void *return_address = (const void *)uc->uc_mcontext.arm_pc;
#endif

	sigsegv_outp("\nStack trace:");
	while (return_address) {
		memset(&dl_info, 0, sizeof(Dl_info));
		if (!dladdr((void *)return_address, &dl_info))	break;
		const char *sname = dl_info.dli_sname;	
#if (!defined NO_CPP_DEMANGLE)
		int status;
		char *tmp = __cxa_demangle(sname, NULL, 0, &status);
		if (status == 0 && tmp) {
			sname = tmp;
		}
#endif
		/* No: return address <sym-name + offset> (filename) */
		sigsegv_outp("%02d: %p <%s + %lu> (%s)", ++i, return_address, sname, 
			(unsigned long)return_address - (unsigned long)dl_info.dli_saddr, 
													dl_info.dli_fname);
#if (!defined NO_CPP_DEMANGLE)
		if (tmp)	free(tmp);
#endif
		if (dl_info.dli_sname && !strcmp(dl_info.dli_sname, "main")) break;

		if (!frame_pointer)	break;
#if (defined (__x86_64__)) || (defined (__i386__))
		return_address = frame_pointer[1];
		frame_pointer = (const void **)frame_pointer[0];
#elif (defined (__arm__))
		return_address = frame_pointer[-1];	
		frame_pointer = (const void **)frame_pointer[-3];
#endif
	}
	sigsegv_outp("Stack trace end.");
}

static void sigsegv_handler(int signo, siginfo_t *info, void *context)
{
	sigsegv_outp("Segmentation Fault!");
	sigsegv_outp("info.si_signo = %d", signo);
	if (info) {
		sigsegv_outp("info.si_errno = %d", info->si_errno);
		sigsegv_outp("info.si_code  = %d (%s)", info->si_code, 
			(info->si_code == SEGV_MAPERR) ? "SEGV_MAPERR" : "SEGV_ACCERR");
		sigsegv_outp("info.si_addr  = %p\n", info->si_addr);
	}

	if (context) {
		const ucontext_t *uc = (const ucontext_t *)context;

		print_reg(uc);
		print_call_link(uc);
	}

	_exit(0);
}

#define SETSIG(sa, signo, func, flags)	\
        do {                            \
            sa.sa_sigaction = func;  	\
            sa.sa_flags = flags;        \
            sigemptyset(&sa.sa_mask);   \
            sigaction(signo, &sa, NULL);\
        } while(0)

static void __attribute((constructor)) setup_sigsegv(void) 
{
	struct sigaction sa;

	SETSIG(sa, SIGSEGV, sigsegv_handler, SA_SIGINFO); 
#if 0
	memset(&sa, 0, sizeof(struct sigaction));
	sa.sa_sigaction = sigsegv_handler;
	sa.sa_flags = SA_SIGINFO;
	if (sigaction(SIGSEGV, &sa, NULL) < 0) {
		perror("sigaction: ");
	}
#endif
}

#if 1
void func3(void)
{
	char *p = (char *)0x12345678;
	*p = 10;
}

void func2(void)
{
	func3();	
}

void func1(void)
{
	func2();
}

int main(int argc, const char *argv[])
{
	func1();	
	exit(EXIT_SUCCESS);
}
#endif

ucontext_t以及ucontext族函数
ucontext_t结构体
ucontext_t结构体定义,一个ucontext_t至少包括以下四个成员,可能依据不同系统包括其他不同的成员。

#include <ucontext.h>
typedef struct ucontext_t {
struct ucontext_t* uc_link;
sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;

};
1
2
3
4
5
6
7
8
类成员解释:

uc_link:为当前context执行结束之后要执行的下一个context,若uc_link为空,执行完当前context之后退出程序。
uc_sigmask : 执行当前上下文过程中需要屏蔽的信号列表,即信号掩码
uc_stack : 为当前context运行的栈信息。
uc_mcontext : 保存具体的程序执行上下文,如PC值,堆栈指针以及寄存器值等信息。它的实现依赖于底层,是平台硬件相关的。此实现不透明。
————————————————
版权声明:本文为CSDN博主「langzi989」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014630623/article/details/89020088

ucontext族函数
ucontext族函数主要包括以下四个:

#include <ucontext.h>
void makecontext(ucontext_t* ucp, void (func)(), int argc, …);
int swapcontext(ucontext_t
olducp, ucontext_t* newucp);
int getcontext(ucontext_t* ucp);
int setcontext(const ucontext_t* ucp);
1
2
3
4
5
makecontext:初始化一个ucontext_t,func参数指明了该context的入口函数,argc为入口参数的个数,每个参数的类型必须是int类型。另外在makecontext之前,一般需要显示的初始化栈信息以及信号掩码集同时也需要初始化uc_link,以便程序退出上下文后继续执行。
swapcontext:原子操作,该函数的工作是保存当前上下文并将上下文切换到新的上下文运行。
getcontext:将当前的执行上下文保存在ucp中,以便后续恢复上下文
setcontext : 将当前程序切换到新的context,在执行正确的情况下该函数直接切换到新的执行状态,不会返回。
注意:setcontext执行成功不返回,getcontext执行成功返回0,若执行失败都返回-1。若uc_link为NULL,执行完新的上下文之后程序结束。
————————————————
版权声明:本文为CSDN博主「langzi989」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u014630623/article/details/89020088

#include <ucontext.h>
#include <iostream>
#include <unistd.h>

void newContextFun() {
  std::cout << "this is the new context" << std::endl;
}

int main() {
  char stack[10*1204];

  //get current context
  ucontext_t curContext;
  getcontext(&curContext);

  //modify the current context
  ucontext_t newContext = curContext;
  newContext.uc_stack.ss_sp = stack;
  newContext.uc_stack.ss_size = sizeof(stack);
  newContext.uc_stack.ss_flags = 0;

  newContext.uc_link = &curContext;

  //register the new context
  makecontext(&newContext, (void(*)(void))newContextFun, 0);
  swapcontext(&curContext, &newContext);
  printf("main\n");

  return 0;
}

setStyleSheet

使用setStyleSheet来设置图形界面的外观:
  QT Style Sheets是一个很有利的工具,允许定制窗口的外观,此外还可以用子类QStyle来完成,他的语法很大比重来源于html的CSS,但是适用于窗口

Style Sheets是文字性的设定,对于整个应用程序可以使用QApplication::setStyleSheet() 或者对应一个窗口可以使用QWidget::setStyleSheet(),如果好几个样式表在不同的层次上设定,QT将会集合所有的样式表来设定外观,这称作级串联

1 //例如:下面的样式表指定所有的QLineEdit应该用黄色作为他们的背景颜色,所有的核对框应该用红色作为他们的文本颜色
2 QLineEdit { background: yellow }
3 QCheckBox { color: red } 

对于这种定制,样式表比palette调色板更强大,例如使用QPalette::Button role来设定一个按钮为红色可能引起危险。对于单独使用QPalette很难完成的定制,样式表可以指定样式表作用于当前窗口样式顶部,这意味这应用程序讲看起来尽可能的自然,但是任何样式表系统参数应该考虑,不像QPalette那样,样式表提供检查,如果你设定了一个按钮的背景颜色为红色,你应该确定在所有的平台按钮将会有一个红色的背景,除此,Qt Designer提供样式表集成环境,使得在不同的窗口样式中更容易看到样式表的效果。

此外,样式表可以用来为你的应用程序提供一个出众的外观,不需要使用子类QStyle,例如,可以指定任意的图片为单选按钮和核对按钮,来使它们出众,使用这个技术,也可以获得辅助的定制,这将使用几个子类,例如指定style hint(样式暗示),可以参看例子 Style Sheet。当样式表有效时候,使用QWidget::style()可以返回QStyle。

样式表语法:样式表语法基本和HTML CSS语法一致。样式表包含了样式规则序列,样式规则有一个和组成,指定哪些窗口将会被这些规则影响,指定哪些属性将会被设定在窗口上,例如QPushButton{color:red}。在上面的规则中,QPushButton是,{color:red}是,这个规则指定QPushButton和他的子类将使用红色作为前景颜色,就是字体颜色,并且对大小写没有分别,对于color,ColoR,COLOR是一样的。

​  几个可以同时被列出,使用逗号",“来分开各个,例如:QPushButton, QLineEdit, QComboBox { color: red };部分是一对 属性:值 对,用{}来括起来,使用分号来分开各个属性,例如QPushButton { color: red; font-family: Arial; line-height: 26px;”>可以参看Qt Style Sheets Reference来查看部件以及样式表的属性列表。

关于样式表的级联属性:

看下面代码的不同

1  btn1->setStyleSheet("QPushButton{color:red}"); //设定前景颜色,就是字体颜色
2  btn1->setStyleSheet("QPushButton{background:yellow}"); //设定背景颜色为红色

1 btn1->setStyleSheet("QPushButton{color:red;background:yellow}");

第一个代码只能显示黄色背景,第二个确实红色字体,黄色背景。所以对于同一个部件,要在同一个setStyleSheet(…)中完全写出来,否则对于该部件来讲,只有最后一个setStyleSheet(…)起作用。

Dialog::Dialog(QWidget *parent) :
 2     QDialog(parent),
 3     ui(new Ui::Dialog)
 4 {
 5     ui->setupUi(this);
 6     this->setWindowFlags(this->windowFlags()&Qt::WindowMaximizeButtonHint&Qt::WindowMinimizeButtonHint);//为对话框添加上最大化和最小化按钮
 7 //    layout=new QBoxLayout(this);
 8     layout1=new QGridLayout(this);
 9     btn1=new QPushButton(this);
10     btn1->setStyleSheet("QPushButton{color:red;background:yellow}"); //设定前景颜色,就是字体颜色
11 //    btn1->setStyleSheet("QPushButton{background:yellow}");
12     btn1->setText("Button1");
13 
14     btn2=new QPushButton(this);
15     btn2->setStyleSheet("QPushButton{color:red; //使用rgb来设定背景颜色
16     btn2->setText("Button2");
17 
18      btn3=new QPushButton(this);
19      btn3->setStyleSheet("QPushButton{background-image:url(image/1.png);background-repeat: repeat-xy;background-position: center;background-attachment: fixed;background-attachment: fixed;background-attachment: fixed;;background-clip: padding}");
20      //设定按钮的背景图片,background-repeat可以设定背景图片的重复规则,这里设定仅在xy方向都重复,所以图片会被重复一次
21      //background-position用来设定图片的位置,是左(left)还是右(right),还是在中间(center),是上(top)还是底部(bottom)
22      //background-attachment用来这定背景图片是否卷动或者和窗口大小相匹配,默认是卷动的
23      btn3->setText("Button3");
24 
25      btn4=new QPushButton(this);
26      btn4->setStyleSheet("QPushButton{border: 3px solid red;border-radius:8px}"); //设定边框宽度以及颜色
27      //可以使用border-top,border-right,border-bottom,border-left分别设定按钮的上下左右边框,
28      //同样有border-left-color, border-left-style, border-left-width.等分别来设定他们的颜色,样式和宽度
29      //border-image用来设定边框的背景图片。
30      //border-radius用来设定边框的弧度。可以设定圆角的按钮
31      btn4->setText("Button4");
32 
33      //字体设定
34      //font-family来设定字体所属家族,
35      //font-size来设定字体大小
36      //font-style来设定字体样式
37      //font-weight来设定字体深浅
38      //height用来设定其高低
39      //selection-color用来设定选中时候的颜色
40      edit1=new QLineEdit(this);
41      edit1->setStyleSheet("QLineEdit{font: bold italic large /"Times New Roman/";font-size:25px;color:rgb(55,100,255);height:50px;border:4px solid rgb(155,200,33);border-radius:15px;selection-color:pink}");
42 
43      //父窗口的设定
44      //icon-size来设定图片大小
45      this->setWindowIcon(QIcon("image/1.png"));
46       this->setStyleSheet("QWidget{background:write url(image/2.png);icon-size:20px 5px}");  //设定整个对话框的背景颜色
47 //      this->setStyleSheet("QWidget{icon-size:20px 5px}");
48     layout1->addWidget(btn1,0,0);
49     layout1->addWidget(btn2,0,1);
50     layout1->addWidget(btn3,1,0);
51     layout1->addWidget(btn4,1,1);
52      layout1->addWidget(edit1,2,0);
53 }
54 
55  
语法:<selector><declaration>
QPushButton{color:red};
前者指定哪些窗口将会被这些规则影响,后者指定哪些属性将会被设定在窗口上
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->resize(400,600);
    ui->tableWidget->resize(200,300);
    ui->tableWidget_2->resize(200,300);
    //隐藏水平头
    ui->tableWidget->horizontalHeader()->setHidden(true);
    ui->tableWidget_2->horizontalHeader()->setHidden(true);
    //设置垂直表头不可用
    ui->tableWidget->verticalHeader()->setSectionsClickable(false);
    ui->tableWidget_2->verticalHeader()->setSectionsClickable(false);
    //设置列的宽度
    ui->tableWidget->verticalHeader()->setMinimumWidth(70);
    ui->tableWidget->setColumnWidth(0,70);
    ui->tableWidget_2->verticalHeader()->setMinimumWidth(70);
    ui->tableWidget_2->setColumnWidth(0,70);
    //初始化两个表
    for(int rows=0;rows<ui->tableWidget->rowCount();rows++)
    {
        for(int columns=0;columns<ui->tableWidget_2->columnCount();columns++)
        {
            ui->tableWidget->setItem(rows,columns,new QTableWidgetItem("linshi"));
            //设置文件居中
            ui->tableWidget->item(rows,columns)->setTextAlignment(Qt::AlignCenter);
        }
    }
    for(int rows=0;rows<ui->tableWidget_2->rowCount();rows++)
    {
        for(int columns=0;columns<ui->tableWidget_2->columnCount();columns++)
        {
            ui->tableWidget_2->setItem(rows,columns,new QTableWidgetItem("linshi"));
            //设置文字居中
            ui->tableWidget_2->item(rows,columns)->setTextAlignment(Qt::AlignCenter);
        }
    }
    QTableWidgetItem *itemT=NULL;
    //设置某行某列不可编辑
    for(int rows=0;rows<ui->tableWidget->rowCount();rows++)
    {
        for(int columns=0;columns<ui->tableWidget->columnCount();columns++)
        {
            if(1 == rows%2)
            {
                itemT=ui->tableWidget->item(rows,columns);
                itemT->setFlags(itemT->flags()&~Qt::ItemIsEnabled);
            }

        }
    }
    //焦点策略
    //设置某个控件为选中状态
    //初始化设置某个控件为选中状态
    ui->tableWidget->setFocus();
    //设置红框为选中状态,行选中为红色背景
//    ui->tableWidget->setStyleSheet("QTableWidget::focus {border: 3px solid #de291f;}"
//                                   "QTableWidget{selection-background-color:red;}");
    /*解释:前者表示焦点策略:border:边界占用三个像素,实线,颜色数值*/
    //选择一行
    //ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
    //只能单选
    //ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);

    //设一个焦点不可选中状态
    //ui->btn1->setFocusPolicy(Qt::NoFocus);
    //焦点切换按键
    /*需要用到:hasFocus()是否被选中
    setfocus() 设置为选中状态*/
    //首先通过单机事件进行切换
    //ui->tableWidget->setFocus();
    //重点QDateTime中的年/月/日 时:分:秒的单个选择,以及上下按键的实现
    /*stepUp()、stepDown()
    并且通过索引来选择单个元素*/

    //设置焦点策略
    //1、设置聚焦策略
    this->setFocusPolicy(Qt::StrongFocus);
    //设置首个焦点选中
    //ui->tableWidget->setFocus();//处于焦点状态
    //ui->tableWidget->setStyleSheet("QTableWidget::focus{border:3px solid #CFCFCF");
    //设置button为tabfocus
    //设置选中框为红色方框,选中内部颜色为红色,上键背景为红色,下键背景为黑色
    ui->tableWidget->setStyleSheet("QTableWidget::focus{border:3px solid #0000ff;}"
                                     "QTableWidget{selection-background-color:green;}"
                                     "QTableWidget::up-button{background-color:red;}"
                                     "QTableWidget::down-button{background-color:black;}");
    ui->tableWidget_2->setStyleSheet("QTableWidget::focus{border:3px solid #de2916;}"
                                     "QTableWidget{selection-background-color:red;}"
                                     "QTableWidget::up-button{background-color:red;}"
                                     "QTableWidget::down-button{background-color:black;}");
    ui->btn1->setFocusPolicy(Qt::TabFocus);
    ui->btn1->setStyleSheet("QPushButton::focus{background-color:blue;}");
        ui->btn1_2->setStyleSheet("QPushButton::focus{background-color:black;}");
    //安装事件过滤器
    ui->tableWidget->installEventFilter(this);
    ui->tableWidget_2->installEventFilter(this);
    ui->btn1->installEventFilter(this);
    ui->btn1_2->installEventFilter(this);


}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_btn1_clicked()
{
    if(ui->tableWidget->hasFocus())
    {
        ui->tableWidget_2->setFocus();
    }else if(ui->tableWidget_2->hasFocus())
    {
        ui->tableWidget->setFocus();
        //设置索引焦点

    }
}

void Widget::on_btn1_2_clicked()
{
    ui->dateTimeEdit->setCurrentSectionIndex(++m_cntDtedit%ui->dateTimeEdit->sectionCount());
    //显示选中状态
    ui->dateTimeEdit->stepBy(0);
    if(m_cntDtedit>=6)
    {
        m_cntDtedit=0;
    }
}
//退出选中状态
void Widget::quit()
{
    ui->tableWidget->setFocus();

}

bool Widget::eventFilter(QObject *obj, QEvent *evt)
{
    if(obj==ui->tableWidget||obj==ui->tableWidget_2||obj==ui->btn1
            ||obj==ui->btn1_2)
    {
        if(evt->type()==QEvent::KeyPress)
        {
            //将事件转化为键盘事件
            QKeyEvent *key_evt=static_cast<QKeyEvent*>(evt);
            //按下tab键执行焦点切换事件
            if(key_evt->key()==Qt::Key_Tab
                    ||key_evt->key()==Qt::Key_Down)
            {
                bool t1=ui->tableWidget->hasFocus();
                bool t2=ui->tableWidget_2->hasFocus();
                bool b1=ui->btn1->hasFocus();
                bool b2=ui->btn1_2->hasFocus();
                if(t1)
                {


                        if(ui->tableWidget->currentRow()<ui->tableWidget->rowCount()-1)
                        {
                            ui->tableWidget->setItem(2,0,new QTableWidgetItem(QString::number(ui->tableWidget->currentRow())));
                            focusNextChild();
                        }
                        else if(ui->tableWidget->currentRow()==ui->tableWidget->rowCount()-1)
                        {
                            ui->tableWidget->setItem(3,0,new QTableWidgetItem(QString::number(ui->tableWidget->currentRow(),10)));
                            ui->tableWidget_2->setFocus();
                        }



                }
                else if(t2)
                {


                        if(ui->tableWidget_2->currentRow()<ui->tableWidget_2->rowCount()-1)
                        {
                            focusNextChild();
                        }
                        else if(ui->tableWidget_2->currentRow()==ui->tableWidget_2->rowCount()-1)
                        {
                            ui->tableWidget_2->setItem(3,0,new QTableWidgetItem(QString::number(ui->tableWidget_2->currentRow(),10)));
                            ui->btn1->setFocus();
                        }


                }else if(b1)
                {
                    focusNextChild();
                    ui->btn1_2->setFocus();
                }
                else if(b2)
                {
                    focusNextChild();
                    ui->tableWidget->setFocus();
                }
            }
        else if(key_evt->key()==Qt::Key_Up)
            {
                bool t1=ui->tableWidget->hasFocus();
                bool t2=ui->tableWidget_2->hasFocus();
                bool b1=ui->btn1->hasFocus();
                bool b2=ui->btn1_2->hasFocus();
                if(t1)
                {
                    if(ui->tableWidget->currentRow()>0)
                    {
                        focusPreviousChild();
                    }else if(ui->tableWidget->currentRow()==0)
                    {
                        ui->btn1_2->setFocus();
                    }
                }else if(t2)
                {
                    if(ui->tableWidget_2->currentRow()>0)
                    {
                        focusPreviousChild();
                    }else if(ui->tableWidget_2->currentRow()==0)
                    {
                        ui->tableWidget->setFocus();
                    }
                }else if(b1)
                {
                    ui->tableWidget_2->setFocus();
                }else if(b2)
                {
                    ui->btn1->setFocus();
                }
            }
        }
    }
    return QWidget::eventFilter(obj,evt);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值