推荐给大学生的几个图形界面方案

Posted 小豆芽Pin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了推荐给大学生的几个图形界面方案相关的知识,希望对你有一定的参考价值。

现在计算机专业的大学生,经常要打各种软件设计比赛或者实验,而凡是参与比赛就会要求写个图形界面。但是,怎么写一个图形界面,在学校的课上基本不会讲!因此,我在这里列出几个好用的图形界面方案,推荐给和我一样的在校大学生。

先声明两句,本文主要还是针对没有时间去系统地学习图形界面编程,但经常要做图形界面编程的同学,所以会尽可能地推荐能快速上手、做出精美界面的方案,故而优先考虑实用性和美观性而不是性能。其次,理论上无论是哪种图形界面方案都能够做出美观性和现代感很强的界面,但是做出同样的好看的界面需要的编码时间却不同,所以虽然我会对每种方案都评出“界面美观”的分数,但这只是说在相同的学习和编码时间的情况下、能达到的界面美观性,所以千万不能有“XXX框架写不出好看的界面”这种观点!

那么,话不多说,开始——

1.Qt

Qt是使用C++编程的经典的图形界面方案,Qt写出的应用可以跨Windows,Linux和macOS三个平台(据说还可在androidios上跑,但基本上没人用过)。

Qt对新手很友好,基本上只要学过C++就能对着教程和视频动手写界面。Qt有独特的信号与槽机制,用起来非常爽。Qt可以借助Qt Creater用拖拽的方式写出一个UI,很适合不习惯写布局代码的小白。

Qt的下载也比较简单,基本上可以找官方的下载方式,大概花一两个小时的时间就能配置完。Qt的代码是非常面向对象的,很适合初学面向对象且对面向对象原理既懵懂又憧憬的同学。Qt的性能也是目前跨端GUI方案中最好的,如果你要设计嵌入式应用,那么Qt或PyQt几乎是必选。

Qt的致命缺点是初学者很难立即写出比较好看的界面,如果想要在Qt中写出精美的界面,请一定要学习Qt里的qss、QPainter和QML。

界面美观:★★

学习资源:★★★★★

编码效率:★★★

上手难度:较低

推荐理由:适合会C++初学者,能够快速写出一个能看的图形界面,性能优秀,适合PC端和嵌入式应用。不适合对界面美观要求高的应用、或者单纯不喜欢使用C++的同学。

展示一个我用Qt写的画图软件:

2.PyQt

PyQt就是Qt的Python版本,是使用Python写的界面。与Qt相比,PyQt使用Python语法,更简单易学,而且PyQt和Qt的接口几乎一样,所以已经会Qt的同学可以立即学会PyQt。

PyQt的优点是下载很方便,只需要pip install PyQt5。如果你不会Qt,也可以直接学习PyQt,网上关于PyQt的学习资源也很多。PyQt的写法也和Qt完全一致,区别只是编程语言而已。

当然,PyQt也有Qt的缺点,如果要做出精致到堪称华丽的界面的话,那还是需要花一番功夫的。

界面美观:★★

学习资源:★★★★★

编码效率:★★★★

上手难度:低

推荐理由:适合会写Python的同学或者需要用到Python中一些库的应用。性能也很优秀,适合PC端和嵌入式。Python语言制作图形界面的必选框架。不适合对界面美观要求高的应用。

展示我用PyQt写的答题软件(为了达到这样的效果我几乎花了一个星期在界面编程上...):

3.JavaFX

JavaFX是Java语言编写桌面图形界面的首选框架,适用于桌面端程序。Qt有的功能基本上JavaFX都有,包括对新手很友好的拖拽生成UI(需要下载SceneBuilder)。

JavaFX本身不需要下载,只需用Maven或Gradle引入依赖就行。JavaFX对样式表的支持比Qt更好,所以一些简单的风格化在JavaFX中会更容易做到。JavaFX网上的资料也比较多,可以找到成体系的教程和视频。JavaFX严格遵循MVC,在面向对象上比Qt要更加刻板。

受益于Java的库生态,你可以轻松地在maven.org上找到很多JavaFX的美化库并且加入你项目的依赖,这里推荐一个JMetro。

但是,JavaFX有致命缺点,那就是没有像Qt一样提供信号与槽机制。这一点在后期非常劝退,经常要保存父窗口的数据和传入回调函数。这也使得JavaFX的编码体验可能不如Qt。以及使用JavaFX很早就会遇到多线程问题,一个runLater就要捣鼓好久。

界面美观:★★★

学习资源:★★★★

编码效率:★★★

上手难度:中

推荐理由:适合不得不使用Java编写图形界面的情况,也适合只会用Java的同学。JavaFX在界面美化方面做得稍微比Qt要好。但是没有信号与槽确实使得编码难度变大。

展示一下我用JavaFX写的仿微信软件(大二学期的课程实践课写的, Mugi聊天室这个名字取自Summer Pockets的角色紬Tsumugi):

4.Vue+Flask

前后端分离的Web应用方案,即一个前端框架+一个后端框架的组合。这里选择了其中比较容易学的Vue+Flask的方案。Vue可以替换成React、Svelte等,甚至VanillaJS。Flask也可以替换成FastAPI,或者Java的SpringBoot。

这套方案只能用于写Web端的程序,也就是在浏览器中打开的网页应用,同时也要求你有一定的Web技术和服务器配置基础,一般建议两人以上合作完成。使用的语言是javascript(包括html与CSS)和Python。

受益于Vue简单的语法和JS生态,你可以很轻松地用Vue写出精致好看的界面,更有ElementUI和vuetify等优秀的组件库可供使用。Flask优雅的接口配合Python中丰富的库,简直抹去了后端的一切细枝末节。很多云服务厂商也会提供可以直接使用的Flask工具包(如宝塔界面就有提供开箱即用的Python环境),非常便利。

如果要学习Vue和Flask,我的建议都是直接去学习它们的官方文档,两个的官方文档都是非常适合初学者逐渐过渡学习的。参考:简介 | Vue.js 欢迎来到 Flask 的世界 — Flask中文文档(2.1.x)

界面美观:★★★★★

学习资源:★★★★★

编码效率:★★★★ (如果使用TypeScript的话就再加一颗星)

上手难度:中

推荐理由:Web端应用的首选,很容易做出精美的界面,以及可以考虑许多与之类似的方案。缺点是只能做在浏览器中运行的Web应用,对PC端和手机端不友好。

展示一个我用Vue做的登录界面:

5.Electron / Tauri

一般来说像Vue这种前端框架只能写Web应用,但是Electron.js却可以让它能够写桌面应用程序,如同你的PC上的一个软件一样。

这套方案的特点就是用前端框架写桌面应用,写出来的软件可以在PC上打开和运行,可在Windows、MacOS和Linux上运行。Electron.js学习难度也不大,基本的概念可以通过官网教程或视频理解。需要你掌握至少一个前端框架(如Vue),以及Node.js。

Electron.js的缺点是打包出来的包体积很大,一个exe的大小可能就是100M起步,这是因为Electron.js本身封装了一个Chrome浏览器,而且占用内存也很大。Tauri则解决了这个问题,Tauri是一个类似Electron.js的框架,也是用前端生态写桌面软件。Tauri打包出来的软件体积要小得多,可以做到几Mb的大小。但是Tauri的后台是用Rust编写的(而不是Electron.js中的Node.js),高性能的同时也需要你学习Rust这门语言。

界面美观:★★★★★

学习资源:★★★★

编码效率:★★★★

上手难度:Electron:中;Tauri:较高

推荐理由:前端程序员的福音,用前端生态写桌面软件!其中Electron打包体积大,Tauri需要学习Rust,各有优劣。相对来说Electron的生态要好于Tauri。

展示一个我用Tauri试水做的程序,可以看到这个程序是运行在PC上的:

6.uniapp+uniCloud

uniapp是一套基于Vue的全平台界面方案,也就是说uniapp可以用来写运行在Web端、手机端和小程序端(如微信小程序)的软件。只要会写Vue,就可以做出全平台的应用!uniapp还可以使用uView这种UI组件库,总的来说界面美观度还是有保证的。

uniCloud则是和uniapp配套的一套云服务方案,比自己去配置服务器要方便很多,而且还有免费的云服务空间和云储存服务,非常适合应用不大却需要云资源的场景。需要你会Node.js,以及学习与uniCloud相关的接口。当然,你也可以不使用uniCloud,只使用uniapp。

uniapp和uniCloud的官方文档都十分全面,一般建议直接参考官方文档学习。uniapp还提供HBuilderX这个专门的IDE。

缺点是不适合大型的应用,我一般在打比赛时做展示来用,或者用在个人的小项目。如果软件用户人数超过1000人,那么这可能不是一个合适的稳定的方案。

界面美观:★★★★★

学习资源:★★★★

编码效率:★★★★

上手难度:中

 推荐理由:一站式的全平台软件方案!基于Vue的语法,可以实现Web、手机端和小程序端的应用。uniCloud对于不会配置服务器的同学非常友好,而且免费的云服务真的很香。缺点是,出于稳定性考虑,一般不用于大的项目。

7.Flutter

我注意到最近也有人使用Flutter做项目去参加比赛的,所以不妨介绍一下Flutter这个框架。

Flutter是一个可以实现Android、iOS、Windows、MacOS、Linux和Web端的全平台跨端框架,主打手机端跨端。Flutter使用的编程语言是Dart,其语法类似Java。

Flutter还是一个比较新的框架,但是它的跨平台特性很适合小团队和打比赛。因为它只需一套代码,就可以在Android和iOS上运行,以及Windows和MacOS。Flutter的生态尚在发展中,还没有成型的组件库,但是它原始的组件就已经能达到比较好的界面美观性。

如果要学习Flutter,我建议一边学Flutter一边学Dart,经常去pub.dev上搜搜,并且最好能够去看Flutter Widget of the Week的视频。由于暂时没有找到好的教程,因此不作特别推荐。Flutter的学习难度相对较大。

Flutter的语法比原生的Android简单,但是不如Swift和Jetpack Compose,其嵌套式的语法也是它的缺点之一。

界面美观:★★★★

学习资源:★★★

编码效率:★★★

上手难度:高

推荐理由:Flutter是真正的全平台跨端方案,无论是手机端还是电脑都能运行。但是学习难度大,目前还没找到比较好的学习资源。

我常用的几个 VueUse 最佳组合,推荐给你们!

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

Vueuse拥有大量出色的组合。但是量太大,要把它们全部看完可能会让人抓不到重点。下面来介绍一些有用到的组合,它们如下:

  1. onClickOutside
  2. useFocusTrap
  3. useHead
  4. useStorage
  5. useVModel
  6. useImage
  7. useDark

1. onClickOutside

检测点击非常简单。但是,当点击发生在一个元素之外时,如何检测?那就有点棘手了。但使用VueUse中的 onClickOutside 组件就很容易能做到这点。代码如下:

<script setup>
import  ref  from 'vue'
import  onClickOutside  from '@vueuse/core'

const container = ref(null)
onClickOutside(container, () => alert('Good. Better to click outside.'))
</script>

<template>
  <div>
    <p>Hey there, here's some text.</p>
    <div class="container" ref="container">
      <p>Please don't click in here.</p>
    </div>
  </div>
</template>

为想要追踪的 container 元素创建一个 ref :

const container = ref(null);

然后我们用元素上的ref属性把它变成一个模板ref

<div class="container" ref="container">
  <p>Please don't click in here.</p>
</div>

有了容器的ref 之后,我们把它和一个处理程序一起传递给onClickOutside组合。

onClickOutside(
  container,
  () => alert('Good. Better to click outside.')
)

这种可组合对于管理窗口或下拉菜单很有用。当用户点击下拉菜单以外的地方时,你可以关闭它。

模态框也通常表现出这种行为。

事例地址:https://stackblitz.com/edit/vue3-script-setup-with-vite-18scsl?file=src%2FApp.vue

2.useFocusTrap

为了拥有可访问的应用程序,正确地管理焦点非常重要。

没有什么比不小心在模态后面加tab,并且无法将焦点返回到模态更糟糕的了。这就是焦点陷阱的作用。

将键盘焦点锁定在一个特定的DOM元素上,不是在整个页面中循环,而是在浏览器本身中循环,键盘焦点只在该DOM元素中循环。

下面是一个使用VueUse的useFocusTrap的例子:

<script setup>
import  ref  from 'vue'
import  useFocusTrap  from '@vueuse/integrations/useFocusTrap'

const container = ref(null)
useFocusTrap(container,  immediate: true )
</script>

<template>
  <div>
    <button tab-index="-1">Can't click me</button>
    <div class="container" ref="container">
      <button tab-index="-1">Inside the trap</button>
      <button tab-index="-1">Can't break out</button>
      <button tab-index="-1">Stuck here forever</button>
    </div>
    <button tab-index="-1">Can't click me</button>
  </div>
</template>

immediate设置为true,页面加载时,焦点将被放置在 container 元素中。然后,就不可能在该容器之外的地方做标签。

到达第三个按钮后,再次点击tab键将回到第一个按钮。

就像onClickOutside一样,我们首先为 container 设置了模板ref

const container = ref(null)
<div class="container" ref="container">
  <button tab-index="-1">Inside the trap</button>
  <button tab-index="-1">Can't break out</button>
  <button tab-index="-1">Stuck here forever</button>
</div>

然后我们把这个模板引用传递给useFocusTrap组合。

useFocusTrap(container,  immediate: true );

immediate 选项将自动把焦点设置到容器内第一个可关注的元素上。

事例地址:https://stackblitz.com/edit/vue3-script-setup-with-vite-eocc6w?file=src%2FApp.vue

3. useHead

VueUse为我们提供了一种简单的方法来更新我们应用程序的 head 部分–页面 title、scripts和其他可能放在这里的的东西。

useHead 组合要求我们首先设置一个插件

import  createApp  from 'vue'
import  createHead  from '@vueuse/head'
import App from './App.vue'

const app = createApp(App)
const head = createHead()

app.use(head)
app.mount('#app')

一旦我们使用了这个插件,我们就可以随心所欲地更新标题部分。在这个例子中,我们将在一个按钮上注入一些自定义样式。

<script setup>
import  ref  from 'vue'
import  useHead  from '@vueuse/head'

const styles = ref('')
useHead(
  // Inject a style tag into the head
  style: [ children: styles ],
)

const injectStyles = () => 
  styles.value = 'button  background: red '

</script>

<template>
  <div>
    <button @click="injectStyles">Inject new styles</button>
  </div>
</template>

首先,我们创建一个ref来表示我们要注入的样式,默认为空:

const styles = ref('');

第二,设置 useHead 将样式注入到页面中。

useHead(
  // Inject a style tag into the head
  style: [ children: styles ],
)

然后,添加注入这些样式的方法:

const injectStyles = () => 
  styles.value = 'button  background: red '

当然,我们并不局限于注入样式。我们可以在我们的<head>中添加任何这些内容:

  1. title
  2. meta tags
  3. link tags
  4. base tag
  5. style tags
  6. script tags
  7. html attributes
  8. body attributes

事例地址:https://stackblitz.com/edit/vue3-script-setup-with-vite-szhedp?file=src%2FApp.vue

4. useStorage

useStorage真的很酷,因为它会自动将 ref 同步到 localstorage,事例如下:

<script setup>
import  useStorage  from '@vueuse/core'
const input = useStorage('unique-key', 'Hello, world!')
</script>

<template>
  <div>
    <input v-model="input" />
  </div>
</template>

第一次加载时, input 显示 ‘Hello, world!’,但最后,它会显示你最后在 input 中输入的内容,因为它被保存在localstorage中。

除了 localstorage,我们也可以指定 sessionstorage:

const input = useStorage('unique-key', 'Hello, world!', sessionStorage)

当然,也可以自己实现存储系统,只要它实现了StorageLike接口。

export interface StorageLike 
  getItem(key: string): string | null
  setItem(key: string, value: string): void
  removeItem(key: string): void

5. useVModel

v-model指令是很好的语法糖,使双向数据绑定更容易。

useVModel更进一步,摆脱了一堆没有人真正想写的模板代码。

<script setup>
import  useVModel  from '@vueuse/core'

const props = defineProps(
  count: Number,
)
const emit = defineEmits(['update:count'])

const count = useVModel(props, 'count', emit)
</script>

<template>
  <div>
    <button @click="count = count - 1">-</button>
    <button @click="count = 0">Reset to 0</button>
    <button @click="count = count + 1">+</button>
  </div>
</template>

在这个例子中,我们首先定义了要附加到v-model上的 props:

const props = defineProps(
  count: Number,
)

然后我们发出一个事件,使用v-model的命名惯例update:<propName>:

const emit = defineEmits(['update:count'])

现在,我们可以使用useVModel组合来将 prop和事件绑定到一个ref

const count = useVModel(props, 'count', emit)

每当 prop 发生变化时,这个 count 就会改变。但只要它从这个组件中被改变,它就会发出update:count事件,通过v-model指令触发更新。

我们可以像这样使用这个 Input 组件。

<script setup>
import  ref  from 'vue'
import Input from './components/Input.vue'

const count = ref(50)
</script>

<template>
  <div>
    <Input v-model:count="count" />
     count 
  </div>
</template>

这里的count ref是通过v-model绑定与 Input组件内部的count ref同步的。

事例地址:https://stackblitz.com/edit/vue3-script-setup-with-vite-ut5ap8?file=src%2FApp.vue

6. useImage

随着时间的推移,web应用中的图像变得越来越漂亮。我们已经有了带有srcset的响应式图像,渐进式加载库,以及只有在图像滚动到视口时才会加载的库。

但你知道吗,我们也可以访问图像本身的加载和错误状态?

我以前主要通过监听每个HTML元素发出的onloadonerror事件来做到这一点,但VueUse给我们提供了一个更简单的方法,那就是useImage组合。

<script setup>
import  useImage  from '@vueuse/core'

// Change this to a non-existent URL to see the error state
const url = 'https://source.unsplash.com/random/400x300'
const  isLoading, error  = useImage(
  
    src: url,
  ,
  
    // Just to show the loading effect more clearly
    delay: 2000,
  
)
</script>

<template>
  <div>
    <div v-if="isLoading" class="loading gradient"></div>
    <div v-else-if="error">Couldn't load the image :(</div>
    <img v-else :src="url" />
  </div>
</template>

第一步,通过useImage 设置图片的src:

const  isLoading, error  = useImage( src: url )

获取它返回的isLoadingerror引用,以便跟踪状态。这个组合在内部使用useAsyncState,因此它返回的值与该组合的值相同。

安排好后,useImage 就会加载我们的图像并将事件处理程序附加到它上面。

我们所要做的就是在我们的模板中使用相同的URL来使用该图片。由于浏览器会重复使用任何缓存的图片,它将重复使用由useImage加载的图片。

<template>
  <div>
    <div v-if="isLoading" class="loading gradient"></div>
    <div v-else-if="error">Couldn't load the image :(</div>
    <img v-else :src="url" />
  </div>
</template>

在这里,我们设置了一个基本的加载和错误状态处理程序。当图片正在加载时,我们显示一个带有动画渐变的占位符。如果有错误,我们显示一个错误信息。否则我们可以渲染图像。

UseImage 还有其他一些很棒的特性!如果想让它成为响应式图像,那么它支持srcsetsizes属性,这些属性在幕后传递给img元素。

如果你想把所有内容都放在模板中,还有一个无渲染组件。它的工作原理与组合的相同:

<template>
	<UseImage src="https://source.unsplash.com/random/401x301">
    <template #loading>
			<div class="loading gradient"></div>
		</template>
    <template #error>
			Oops!
		</template>
  </UseImage>
</template>

事例:https://stackblitz.com/edit/vue3-script-setup-with-vite-d1jsec?file=src%2FApp.vue

7. 暗黑模式 useDark

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F3SJ5lJE-1658277039009)(/img/bVc09yk)]

最近,每个网站和应用程序似乎都有暗黑模式。最难的部分是造型的改变。但是一旦你有了这些,来回切换就很简单了。

如果你使用的是Tailwind,你只需要在html元素中添加dark类,就可以在整个页面中启用。

<html class="dark"><!-- ... --></html>

然而,在黑暗模式和光明模式之间切换时,有几件事需要考虑。首先,我们要考虑到用户的系统设置。第二,我们要记住他们是否已经推翻了这个选择。

VueUse的useDark组合性为我们把所有这些东西都包起来。默认情况下,它查看系统设置,但任何变化都会被持久化到localStorage,所以设置会被记住。

<script setup>
import  useDark, useToggle  from '@vueuse/core'

const isDark = useDark()
const toggleDark = useToggle(isDark)
</script>

<template>
  <div class="container">
    Changes with dark/light mode.

    <button @click="toggleDark()">
			Enable  isDark ? 'Light' : 'Dark'  Mode
		</button>
  </div>
</template>

黑暗模式的样式:

.dark .container 
  background: slategrey;
  color: white;
  border-color: black;


.dark button 
  background: lightgrey;
  color: black;


.dark body 
  background: darkgrey;

如果你没有使用Tailwind,你可以通过传入一个选项对象来完全定制黑暗模式的应用方式。下面是默认的Tailwind:

const isDark = useDark(
  selector: 'html',
  attribute: 'class',
  valueDark: 'dark',
  valueLight: '',
)

也可以提供一个onChanged处理程序,这样你就可以编写任何你需要的Javascript。这两种方法使你可以使它与你已有的任何造型系统一起工作。

总结

Vueuse 拥有一个巨大的库,其中包含出色的组合,而我们在这里只涵盖了其中的一小部分。我强烈建议你花些时间去探索这些文档,看看所有可用的东西。这是一个非常好的资源,它将使你免于大量的模板代码和不断地重新发明车轮。


编辑中可能存在的bug没法实时知道,事后为了解决这些bug,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug

作者:Noveo 译者:小智 来源:vuemastery

原文:https://www.vuemastery.com/blog/best-vueue-composables

交流

有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。

以上是关于推荐给大学生的几个图形界面方案的主要内容,如果未能解决你的问题,请参考以下文章

pyqt5通过qt designer 设计方式连接多个UI图形界面

Qt for windows消息循环libqxt分析和wince快捷键处理

在嵌入式 Linux 设备上使用 Flutter 开发图形界面

在嵌入式 Linux 设备上使用 Flutter 开发图形界面

在嵌入式 Linux 设备上使用 Flutter 开发图形界面

结对编程——带UI的小初高数学学习软件