探索 Electron:助力文档操作应用快速落地

news2024/11/15 13:57:04

Electron是一个开源的桌面应用程序开发框架,它允许开发者使用Web技术(如 HTML、CSS 和 JavaScript)构建跨平台的桌面应用程序,它的出现极大地简化了桌面应用程序的开发流程,让更多的开发者能够利用已有的 Web 开发技能来构建功能强大且跨平台的应用程序,这对于提升开发效率和应用程序的快速交付具有重要意义。

初始化项目

安装框架:今天博主这里用到electron-vite构建器开发桌面端应用,对项目进行一个初始化,这里我们用到该构建器中的react框架开始今天项目的书写,如果想了解vue框架搭建的项目,参考我之前的文章:地址 ,废话不多说直接开始我们今天的项目讲解:

终端执行如下命令安装electron项目:

npm create @quick-start/electron@latest

这里输入完项目的名称之后,选择今天要讲解的react模板即可:

根据需求选择是否使用TS,博主写项目一般都选择TS,这里也就选择TS吧:

是否添加electron更新的插件,当然必须选上: 

是否下载electron的镜像代理,这里也选上吧:

配置完成之后,切换到对应项目目录,终端执行 npm i 安装好依赖,终端执行 npm run dev,可以看到我们的项目已经跑起来了,初识页面看着也是非常的简约大气,项目也是给我们默认配置好了相关的插件便于代码的书写:

配置UI框架:因为这里我们使用了react框架搭建项目,所以这里的UI组件库的话还是采用常用的antd进行样式的搭建吧,终端执行如下命令进行安装:

npm install antd --save

然后随便引入一个按钮,可以看到我们的组件库已经引入成功了:

配置styled-components:因为这里我们使用了react框架来编写electron项目,所以这里我们使用了styled-components样式库来编写内容样式,详情请参考我之前的文章:地址  。

安装图标库:这里我们使用一个大家场景的图标库Font Awesome,该图标库内容还是比较丰富全面的,并且支持vue和react框架其地址为:地址 ,因为本项目采用react框架,所以这里就以react安装为例吧,终端执行如下命令进行安装:

# 以下三个库都需要进行安装
npm i --save @fortawesome/fontawesome-svg-core # 图标库核心文件
npm i --save @fortawesome/react-fontawesome@latest # react风格图标
npm i --save @fortawesome/free-solid-svg-icons # solid类型的字体库

安装完图标库之后,直接在相应的文件中引入对应的图标即可,示例代码如下:

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTimes, faSearch } from '@fortawesome/free-solid-svg-icons'

// 引入对应图标
<FontAwesomeIcon icon={faSearch} /> // 搜索图标
<FontAwesomeIcon icon={faTimes} /> // 关闭图标

左侧菜单栏

在项目初始化完毕 之后,接下来我们开始我们开始对页面开始编写相应的内容了,为了固定我们的界面大小,这里我们先在主进程中把界面的大小固定住,禁止用户缩放,如下:

然后我们在根组件App.tsx中编写相应的内容模块,这里我们分两部分,左侧是菜单栏,右侧是展示的内容区域,这里我们借助样式组件styled-components开始相应的样式,当然这里我们也写了一下全局样式,清除一下框架默认的样式,代码如下(条理清晰,一目了然):

import styled, { createGlobalStyle } from "styled-components";
// 导入公共组件
import SearchFile from "./components/SearchFile";

const App = () => {
    return (
        <>
            <GlobalStyle />
            <Container>
                <LeftDiv>
                    <SearchFile title={'我的文档'} onSearch={(value: string)=> {
                        console.log(value)
                    }}></SearchFile>
                </LeftDiv>
                <RightDiv>右侧</RightDiv>
            </Container>
        </>
    );
}

export default App;
// 设置全局样式
const GlobalStyle = createGlobalStyle`
    body {
        margin: 0;
        padding: 0;
        font-family: sans-serif;
    }
`
// 样式组件
const Container = styled.div` // 初始容器
    width: 100%;
    height: 100vh;
    display: flex;
`;
const LeftDiv = styled.div` // 左边容器
    width: 30%;
    height: 100%;
    background-color: #008c8c;
`
const RightDiv = styled.div` // 右边容器
    width: 70%;
    height: 100%;
    background-color: #fff;
`

接下来我们开始编写引入的公共组件SearchFile中的内容,这里我们编写了一个逻辑,默认是文字内容,然后用户点击我们设置的搜索的图标样式之后,则变成输入框,用户可以通过回车传递输入的数据给父组件,然后点击esc退出输入框的模式,具体代码如下所示:

import { useState, useEffect, useRef } from 'react'
import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTimes, faSearch } from '@fortawesome/free-solid-svg-icons'

const SearchFile = ({ title, onSearch }: { title: string; onSearch: (value: string) => void }) => {
    const [ searchActive, setSearchActive ] = useState<boolean>(false)
    const [ value, setValue ] = useState<string>('')
    // 获取输入框实例
    const inputRef = useRef<HTMLInputElement>(null)

    // 关闭搜索框
    const closeSearch = () => {
        setSearchActive(false)
        setValue('')
    }
   
    // 监听键盘事件
    useEffect(() => {
        const ListenKeyWord = (e: any) => {
            const { keyCode } = e
            if ( keyCode === 13 && searchActive ) {
                onSearch(value)
            }
            if ( keyCode === 27 && searchActive ) {
                closeSearch()
            }
        }
        document.addEventListener('keyup', ListenKeyWord)
        // 组件加载时获取焦点
        return () => { // 组件卸载时移除监听事件
            document.removeEventListener('keyup', ListenKeyWord)
        }
    }, [searchActive, value, onSearch])
    // 实现输入框聚焦
    useEffect(() => {
        if (searchActive && inputRef.current) {
            inputRef.current.focus()
        }
    }, [searchActive])
    return (
        <>
            {/* 默认文字显示 */}
            { !searchActive && (
                <SearchDiv>
                    <Span>{ title }</Span>
                    <Span onClick={()=> { setSearchActive(true) }}>
                        <FontAwesomeIcon icon={faSearch} />
                    </Span>
                </SearchDiv>

            )}
            {/* 点击文字则显示搜索框 */}
            { searchActive && (
                <SearchDiv>
                    <Input value={value} ref={inputRef} onChange={(e)=> {
                        setValue(e.target.value)
                    }} />
                    <Span onClick={closeSearch}>
                        <FontAwesomeIcon icon={faTimes} />
                    </Span>
                </SearchDiv>
            )}
        </>
    )
}

export default SearchFile
// 样式组件
const SearchDiv = styled.div`
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #fff;
`
const Span = styled.span`
    color: #fff;
    padding: 5px 15px;
    font: normal 16px/40px '微软雅黑';
    cursor: pointer;
    user-select: none;
`
const Input = styled.input.attrs({
    type: 'text',
    placeholder: '搜索文件'
})`
    width: 100%;
    height: 25px;
    border: none;
    outline: none;
    border-radius: 1px;
    margin-left: 10px;
`

最终呈现的效果如下所示:

接下来开始对左侧的文件菜单栏样式做一个调整,这里我们将其也抽离出一个公共组件,因为文件名称也是要进行输入框来修改,也是要借助监听键盘事件,这里我们将其抽离出一个hooks函数:

// 自定义监听键盘事件hook函数
import { useState, useEffect } from 'react';

export const useKeyHandler = (code: number) => {
    const [ keyPressed, setKeyPressed ] = useState<boolean>(false);
    
    const keyDownHandler = (e: any) => { if (e.keyCode == code) setKeyPressed(true) }; // 按下键盘
    const keyUpHandler = (e: any) => { if (e.keyCode == code) setKeyPressed(false) } // 抬起键盘
    useEffect(() => {
        document.addEventListener('keydown', keyDownHandler);
        document.addEventListener('keyup', keyUpHandler);
        return () => {
            document.removeEventListener('keydown', keyDownHandler);
            document.removeEventListener('keyup', keyUpHandler);
        }
    });
    return keyPressed;
}

然后接下来我们开始创建文件列表菜单名称,这里我们在根组件中把数据通过props传递给文件列表组件,组件拿到数据后,根据情况进行渲染:

组件拿到数据之后开始对页面进行一个渲染,这里就不再一一赘述了,都是正常的vue代码:

最终得到的效果如下所示:

然后如法炮制,在左侧的底部下面再放置两个按钮,新建和导入,如下:

import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'

interface ButtonItemProps {
    title: string,
    btnClick?: () => void,
    icon: any
}

const ButtonItem = ({ title, btnClick, icon }: ButtonItemProps) => {
    return (
        <BtnDiv>
            <FontAwesomeIcon style={{ marginRight: '10px' }} icon={icon} />
            { title }
        </BtnDiv>
    )
}

export default ButtonItem
// 样式组件
const BtnDiv = styled.div`
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 40px;
    cursor: pointer;
    font-size: 18px;
    user-select: none;
    &:hover {
        background-color: #15ad7a;
        border-radius: 5px 5px 5px 5px;
    }
    &:active {
        background-color: #00fc17;
    }
`

最终呈现的效果如下所示:

右侧主内容

接下来开始编写右侧内容区域,首先我们先完成顶部tab标签页的静态内容,这里我们在App根组件中设置TabList组件,然后传入相关数据,以及激活标签页,未保存、点击和关闭回调:

然后开始搭建静态页面,如下所示:

import styled from 'styled-components'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTimes, faCircle } from '@fortawesome/free-solid-svg-icons'

interface TabListProps {
    files: any[]
    activeItem: string
    unSaveItems: any[]
    clickItem: (id: string) => void
    closeItem: (id: string) => void
}

const TabList = ({ files, activeItem, unSaveItems, clickItem, closeItem }: TabListProps) => {
    return (
        <TabDiv>
            { files.map(item => {
                let isUnSave = unSaveItems.includes(item.id)
                return (
                    <TabItem 
                        $isActive={activeItem === item.id}
                        key={item.id} 
                        onClick={(e: any) => { e.preventDefault(); clickItem(item.id) }}
                    >
                        <TabItemName>{ item.title }</TabItemName>
                        <TabItemIcon onClick={(e: any) => { e.stopPropagation(); closeItem(item.id) }}>
                            <FontAwesomeIcon className='close' icon={faTimes} />
                        </TabItemIcon>
                        { isUnSave && (
                            <FontAwesomeIcon className='circle' icon={faCircle} />
                        ) }
                    </TabItem>
                )
            }) }
        </TabDiv>
    )
}

最终呈现的效果如下所示:

接下来开始编写右侧主内容中下侧的编辑器内容,这里我们借助一个开源的简易的react编辑器插件,其官方网址为:地址 ,如下所示:

终端执行如下命令进行安装:

npm install --save react-simplemde-editor easymde

安装完成之后,通过一段简单的示例代码进行演示:

import SimpleMDE from "react-simplemde-editor";
import "easymde/dist/easymde.min.css";

<SimpleMDE
    value={initFiles[1].body}
    onChange={(value: string) => console.log("编辑", value)}
    options={{
        autofocus: true, // 自动获得焦点
        spellChecker: false, // 拼写检查
        status: true, // 状态栏
        minHeight: "470px", // 最小高度
    }}
/>

最终呈现的效果如下所示,可以看到我们的编辑器已经被成功渲染出来了:

这里我们默认都是把上方的tab标签页都给写死了,这里我们先把写死的内容参数去掉,判断如果用户没有点击文件的话,默认右侧的内容区域是不显示内容的,这里我们给一个提示,根据是否有激活的tabid来判断:

const [files, setFiles] = useState<filesTypes[]>(initFiles); // 文件列表
const [activeId, setActiveId] = useState<string>(""); // 当前激活的tab
const [openIds, setOpenIds] = useState<string[]>([]); // 打开的tab
const [unSaveIds, setUnSaveIds] = useState<string[]>([]); // 未保存的tab

// 计算已打开的所有文件信息
const getOpenFiles = openIds.map((id) => {
    return files.find((file) => file.id === id);
});

// 计算正在编辑的文件信息
const activeFile = files.find((file) => file.id === activeId);

这里根据判断参数渲染内容:

{ activeFile ? (
    <>
        <TabList 
            files={getOpenFiles}   
            activeItem={activeId} 
            unSaveItems={unSaveIds} 
            clickItem={(id: string)=>{ console.log("点击", id)}}
            closeItem={(id: string)=>{ console.log("关闭", id)}}
        />
        <SimpleMDE
            value={activeFile.body}
            onChange={(value: string) => console.log("编辑", value)}
            options={{
                autofocus: true, // 自动获得焦点
                spellChecker: false, // 拼写检查
                status: true, // 状态栏
                minHeight: "470px", // 最小高度
            }}
        />
    </>
) : (
    <AdvertisementDiv>
        <AdvertisementImgs src={img} title="csdn博主 '亦世凡华、'" onClick={()=> {
            window.open("https://blog.csdn.net/qq_53123067?spm=1000.2115.3001.5343")
        }} />
        <AdvertisementTitle>当前暂无数据<br/>(PS: 点击上方图片,求一波关注)</AdvertisementTitle>
    </AdvertisementDiv>
) }

最终呈现的效果如下所示:

菜单栏操作

接下来对左侧菜单栏中的按钮进行一个交互操作了,主要分为以下几个方向:

搜索文件:点击搜索图标,在输入框输入相关内容,搜索栏下方的文件列表依据关键字进行呈现,这里我们再呈现设置一下左侧菜单栏的显示内容,如果有搜索出内容就显示搜索的内容,否则默认显示files,代码如下:

const [searchFiles, setSearchFiles] = useState<filesTypes[]>(); // 左侧展示搜索列表于默认列表进行区分
// 计算左侧列表需要展示什么样信息
const fileList = (searchFiles && searchFiles.length > 0) ? searchFiles : files;
// 依据关键字搜索文件
const searchFile = (keyword: string) => {
    const newFiles = files.filter(item => item.title.includes(keyword));
    setSearchFiles(newFiles);
}

tab标签页:接下来我们设置当点击左侧菜单栏中的文件,则打开右侧的tab标签页面,然后当点击tab标签页的时候,切换激活状态,以及点击标签页中的关闭图标进行一个关闭操作:

// 依据关键字搜索文件
const searchFile = (keyword: string) => {
    const newFiles = files.filter(item => item.title.includes(keyword));
    setSearchFiles(newFiles);
}
// 点击左侧文件显示编辑页面
const openItem = (id: string) => {
    setActiveId(id); // 激活tab
    // 判断是否已经打开
    if (!openIds.includes(id)) {
        setOpenIds([...openIds, id]);
    }
};
// 点击某个tab选项时切换当前状态
const changeActive = (id: string) => setActiveId(id)
// 关闭某个tab
const closeFile = (id: string) => {
    const retOpens = openIds.filter((item) => item !== id); // 过滤掉该tab
    setOpenIds(retOpens); // 过滤掉该tab
    if (retOpens.length > 0) {
        setActiveId(retOpens[0]); // 激活第一个tab
    } else {
        setActiveId(""); // 如果没有tab了,则清空激活状态
    }
};

文件内容更新:然后这里当我们对文件里面的body内容进行修改的时候,tab标签页是呈现修改的圆点状态,然后把修改的内容重新添加到当前修改的文件的body中:

// 文件内容更新
const changeFile = (id: string, value: string) => {
    if (!unSaveIds.includes(id)) {
        setUnSaveIds([...unSaveIds, id]); // 添加未保存的tab
    }
    // 某个内容更新后,更新文件列表
    const newFiles = files.map((file) => {
        if (id === file.id) {
            return {...file, body: value}; // 更新文件内容
        } else {
            return file;
        }
    });
    setFiles(newFiles); // 更新文件列表
};

删除文件:删除文件很简单,直接拿到当前要删除的文件id进行一个过滤,然后顺便关闭可能正在打开的tab标签内容即可:

// 删除某个文件项
const deleteItem = (id: string) => {
    const newFiles = files.filter(item => item.id !== id);
    setFiles(newFiles);
    // 删除后,关闭可能正在打开的tab
    closeFile(id);
}

重命名文件:重命名文件的话,直接把输入框中输入的内容拿过来,然后计算当前要修改的文件把里面的名称title进行一个替换即可:

// 重命名文件名称
const renameFile = (id: string, newTitle: string) => {
    const newFiles = files.map((file) => {
        if (id === file.id) {
            return {...file, title: newTitle}; // 更新文件内容
        } else {
            return file;
        }
    });
    setFiles(newFiles); // 更新文件列表
}

新建文件:新建文件的话需要对每个文件生成特定的id,所以这里我们使用uuid进行生成唯一标识,终端执行如下命令进行安装:

npm install uuid
// 新建文件
const createNewFile = () => {
    const newId = uuidv4();
    const newFile: any = {
        id: newId,
        title: "",
        body: "## 初始化内容",
        createTime: new Date().getTime(),
        isNew: true
    }
    // 避免连续点击新建
    if (!files.find((file) => file?.isNew)) {
        setFiles([...files, newFile]);
    }
}

最终呈现的效果如下所示:

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

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

相关文章

智慧农业数据集(一)

目录 葡萄叶片病虫害害数据集 茄子果实病虫害数据集 81类水果数据集 小麦叶片病虫害数据集 番茄叶片病害数据集 草莓叶片病虫害数据集 水稻叶片病虫害数据集 菠萝成熟度数据集 10类水果数据集 葡萄叶片病虫害害数据集 数据集下载链接&#xff1a;葡萄叶片病虫害数据集…

几分钟学会搭建一个自己的外卖霸王餐系统

大家好&#xff0c;我是鲸天科技千千&#xff0c;大家都知道我是做小程序开发的&#xff0c;平时会给大家分享一些互联网相关的创业项目&#xff0c;感兴趣的可以跟我关注一下。 搭建一个首先就是要搭建一个自己的霸王餐小程序&#xff0c;我们自己的工作就是把这个小程序推广…

H5 CSS布局样式定位position

1. H5 H5 CSS布局样式定位position 布局是html中非常重要的一部分&#xff0c;而定位在页面布局中也是使用频率很高的方法&#xff0c;本章节为定位在布局中的使用技巧和注意事项。   position定位有4个属性&#xff0c;分别是static(默认&#xff09;&#xff0c;absolute&a…

6芯7芯可旋转电连接器航空插头

概述 可旋转电航空插头是一种能够在旋转或相对运动的部件间稳定传输电气信号或电源的装置&#xff0c;广泛应用于航空航天、自动化设备、医疗设备等多个领域。它的核心在于精密的接触系统&#xff0c;由旋转端和固定端两部分组成&#xff0c;通过金属触点或导电环实现电气连接。…

pyflink 安装和测试

FPY Warning! 安装 apache-Flink # pip install apache-Flink -i https://pypi.tuna.tsinghua.edu.cn/simple/ Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/ Collecting apache-FlinkDownloading https://pypi.tuna.tsinghua.edu.cn/packages/7f/a3/ad502…

华为CNA VRM搭建(使用vmware worfstartion搭建)

创建虚拟机&#xff1a; 自定义→高级 选择硬件兼容性&#xff1a;默认安装版本&#xff0c;如果未来想要将此虚拟机安装到其他电脑&#xff0c;其他电脑版本过低&#xff0c;此时可以向下兼容&#xff0c;这里我们默认版本 稍后安装操作系统&#xff1a; CNA采用Euler OS系统…

合肥鲸天科技的外卖会员卡系统有人做过吗?赚钱吗?

我们先来了解一下这个合肥鲸天科技&#xff0c;通过我在网上找到的资料和企业查询&#xff0c;这家公司还是很有实力的&#xff0c;合肥鲸天科技有限公司也是欢迎有合作的人到公司来进行一个考察和合作其他一些项目的。 外卖会员卡简介绍&#xff1a; 这个外卖会员卡&#xf…

先框架后历元还是先历元后框架?

最近测绘同行高总发现了一个问题&#xff0c;《CH/T 2014-2016 大地测量控制点坐标转换技术规范》中”5.1.4.1 a) 不同ITRF间框架转换参数的历元归算“中历元不明确&#xff0c;不知是观测历元还是目标历元。他和一些同行用一些数据测试验证后认为观测历元更为贴合实际。 ​编…

lftools frida调试小工具

前言 这两天在分析mac程序数据 &#xff0c;偶尔翻到了以前写的frida代码&#xff0c;如下 那个时候刚刚接触frida 调试Mac电脑上的程序&#xff0c;通过tcp转发到自己写的分析数据的工具上…(专门研究了一下Python的异步编程&#xff0c;libuv啥的…&#xff09; 每隔那么久…

21:I2C三:MPU6050的使用

MPU6050的使用 1、MPU6050简介1.1&#xff1a;加速度与姿态测量1.2&#xff1a;陀螺仪与姿态测量1.3&#xff1a;MPU6050内部结构1.4&#xff1a;模块内部寄存器 2、程序模拟I2C读写MPU60502.1&#xff1a;数据的读取2.2&#xff1a;转换为角度并进行融合 3、片上外设I2C2读写M…

支付域——聚合支付设计

摘要 聚合支付是支付行业的一项重要创新&#xff0c;通过整合多种支付方式&#xff0c;极大简化了支付流程&#xff0c;提升了交易效率&#xff0c;为商户和消费者提供了更加便捷的支付体验。随着移动支付的普及&#xff0c;聚合支付在未来的支付场景中将继续发挥重要作用&…

STL之初始迭代器

迭代器 什么是迭代器? - 迭代器是一种检查容器内元素并且遍历容器内元素的数据类型 迭代器的作用: - 迭代器提供对一个容器中的对象的访问方法&#xff0c;并且定义了容器中对象的范围 为什么需要迭代器? - STL提供每种容器的实现原理各不相同&#xff0c;如果没有迭代器…

心觉:《潜意识显化实操营》首批体验者招募

你是否常常感到困惑&#xff0c;对未来感到迷茫&#xff1f; 你是否在事业、生活中遇到瓶颈&#xff0c;迫切希望突破&#xff1f; 你是否想要把自己3万倍的潜意识能量释放出来 &#xff0c;助力成功&#xff1f; 你是否想要解锁你财富显化的卡点&#xff0c;顺便实现财富自…

CISSP一站通关

依托轻速云维护了一个专注于CISSP备考通关的在线学习平台&#xff0c;提供知识串讲视频&#xff0c;配合大量针对性的习题和重难点习题解析&#xff0c;帮助备考学习者高效学习和巩固知识点。已经帮助100考友顺利通过考试。 知识串讲视频是我主讲的5天直播课程的录屏&#xff0…

C# 反射之动态生成dll/exe

这个可能应该属于反射的高级使用范围了&#xff0c;平常在项目中使用的人估计也不是很多。由于使用反射的话会降低性能&#xff0c;比如之前用到的GetValue、SetValue等之类&#xff0c;但是使用这种方式会大大提高效率&#xff0c;在这里我只想说&#xff0c;都直接写IL指令了…

Qt学习之旅 I

构建一个跨平台的应用(Create A Cross-Platform Application) 目录 构建一个跨平台的应用(Create A Cross-Platform Application) 设计模式 开始构建 Qt是跨平台的C框架&#xff0c;这里&#xff0c;我们将会构建一个简单的C跨平台项目来熟悉QT是如何实现简单的跨平台的。 …

HTB-MarkUp(XXE漏洞、SSH id_rsa密钥)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解MarkUp靶机 渗透过程 信息搜集 服务器开放了22SSH端口、80HTTP端口 和 443HTTPS端口 弱口令登录后台 抓取http 数据包&#xff0c;进行加载 账号密码字典 账号: admin密码: password 利用XXE漏洞 捕…

超分辨率技术之插值算法

&#x1f31e;欢迎莅临我的个人主页&#x1f448;&#x1f3fb;这里是我专注于深度学习领域、用心分享知识精粹与智慧火花的独特角落&#xff01;&#x1f349; &#x1f308;如果大家喜欢文章&#xff0c;欢迎&#xff1a;关注&#x1f377;点赞&#x1f44d;&#x1f3fb;评论…

天融信把桌面explorer.exe删了,导致开机之后无windows桌面,只能看到鼠标解决方法

win10开机进入桌面&#xff0c;发现桌面无了&#xff0c;但是可以ctrlaltdelete调出任务管理器 用管理员权限打开cmd&#xff0c;输入&#xff1a; sfc /scanfilec:\windowslexplorer.exe 在运行C:\windows\Explorer.exe&#xff1b;可以进入桌面&#xff0c;但是隔离几秒钟…

链式二叉树的基本操作(C语言版)

目录 1.二叉树的定义 2.创建二叉树 3.递归遍历二叉树 1&#xff09;前序遍历 2&#xff09;中序遍历 3&#xff09;后序遍历 4.层序遍历 5.计算节点个数 6.计算叶子节点个数 7.计算第K层节点个数 8.计算树的最大深度 9.查找值为x的节点 10.二叉树的销毁 从二叉树…