Android 项目:画图白板APP开发(六)——分页展示 - 教程

news/2025/9/22 18:07:02/文章来源:https://www.cnblogs.com/lxjshuju/p/19105769

        本篇将介绍如何为我们的画板应用添加分页展示功能,让用户可以创建多个画布并在它们之间轻松切换。这章没有啥知识点的讲解,主要介绍一下每页保存的数据结构是什么样的。

一、ListView

        多页数据的管理我们使用ListView。之前有文章讲过ListView这里就不多赘述了,感兴趣的读者可以看看。Android最常用的控件ListView(详解) 。

直接上图例和代码:

//绑定适配器(传入handler)
adapter = new PictureAdapter(mContext,
R.layout.list_item,listDate,handler);
viewMember.lv_tables.setAdapter(adapter);

(1)PictureView.java

//保存某一页的视图信息
public class PictureView {
//保存比例信息
Matrix matrixMain = new Matrix();
//保存撤销和恢复的信息
private ArrayList paintedList = new ArrayList<>();
public ArrayList getCancelList() {
return cancelList;
}
public void setCancelList(ArrayList cancelList) {
this.cancelList = cancelList;
}
public ArrayList getRecoverList() {
return recoverList;
}
public void setRecoverList(ArrayList recoverList) {
this.recoverList = recoverList;
}
private ArrayList cancelList = new ArrayList<>();
private ArrayList recoverList = new ArrayList<>();
//设置一个专门为撤销,回退服务的list
//用来保存每一个操作的意义(可能是单笔的,可能是多笔)
//view上
private Bitmap cacheBitmap;
private Canvas cacheCanvas ;
public PictureView(int width, int height) {
cacheBitmap = Bitmap.createBitmap(width,height,Bitmap.Config.ARGB_4444);
cacheCanvas = new Canvas(cacheBitmap);
}
public ArrayList getPaintedList() {
return paintedList;
}
public void setPaintedList(ArrayList paintedList) {
this.paintedList = paintedList;
}
public Bitmap getCacheBitmap() {
return cacheBitmap;
}
public void setCacheBitmap(Bitmap cacheBitmap) {
this.cacheBitmap = cacheBitmap;
}
public Canvas getCacheCanvas() {
return cacheCanvas;
}
public void setCacheCanvas(Canvas cacheCanvas) {
this.cacheCanvas = cacheCanvas;
}
}

PictureView 是一个数据模型类,用于保存画板中某一页的完整状态信息。

  • (cacheBitmap 和 cacheCanvas):保存当前页面的最终渲染结果
  • paintedList:存储所有的笔画数据

  • cancelList存储已执行但可撤销的操作

  • recoverList存储已撤销但可恢复的操作

  • matrixMain保存缩放、平移、旋转等变换信息

(2)PictureAdapter.java

//适配器
public class PictureAdapter extends ArrayAdapter {
//用来判断当前View上显示的时哪个(默认为第一个)
public int localNum = 1;
private Handler handler;
public PictureAdapter(@NonNull Context context, int resource, @NonNull List objects, Handler handler) {
super(context, resource, objects);
this.handler = handler;
}
@SuppressLint("SetTextI18n")
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
PictureView p = getItem(position);
View view;
//新增一个内部类 ViewHolder,用于对控件的实例进行缓存
ViewHolder viewHolder;
if (convertView==null){
//为每一个子项加载设定的布局
view= LayoutInflater.from(getContext()).inflate(R.layout.list_item,parent,false);
viewHolder= new ViewHolder();
//分别获取 imageview 和 textview 的实例
viewHolder.image =view.findViewById(R.id.iv_image);
viewHolder.imageNum =view.findViewById(R.id.tv_num);
viewHolder.imageDelete=view.findViewById(R.id.bt_delete_item);
viewHolder.layout = view.findViewById(R.id.fl_item);
view.setTag(viewHolder);//将 viewHolder 存储在 view 中
}else {
view=convertView;
viewHolder= (ViewHolder) view.getTag();//重新获取 viewHolder
}
// 设置要显示的内容
viewHolder.image.setImageBitmap(p.getCacheBitmap());
viewHolder.imageNum.setText((position+1)+"");
if((position+1)==localNum){
//008FFB
viewHolder.imageNum.setTextColor(Color.parseColor("#008FFB"));
}else {
viewHolder.imageNum.setTextColor(Color.WHITE);
}
//按钮点击事件(使用handler)
viewHolder.imageDelete.setOnClickListener(v->{
//创建一个线程
Thread t = new Thread(() -> {
Message m = handler.obtainMessage();
m.what = 0x101;
m.arg1 = position;
handler.sendMessage(m);
});
t.start();
});
viewHolder.layout.setOnClickListener(v->{
Thread t =new Thread(() -> {
Message m = handler.obtainMessage();
m.what = 0x102;
m.arg1 = position;
handler.sendMessage(m);
});
t.start();
});
return view;
}
private static class ViewHolder {
TextView imageNum;
ImageView image;
ImageButton imageDelete;
FrameLayout layout;
}
}

PictureAdapter中的点击事件,通过Handler传递

(3)Handler

@SuppressLint("HandlerLeak")
private void initHandler() {
handler = new Handler(Looper.getMainLooper()){
@SuppressLint("SetTextI18n")
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 0x101://删除
//弹出提升框
now = msg.arg1;
new AlertDialog.Builder(mContext).setTitle("提示")
.setMessage("确定要删除 "+ (now+1) +"号视图吗?")
.setPositiveButton("确定", (dialogInterface, i) -> {
//是否为删除的为当前显示的视图
System.out.println("AAAAAAAAAA:   "+ (now+1) +" "+NowNum);
if((now+1)==NowNum&&now==0){
if(total == 1){
Toast.makeText(mContext, "您无法删除最后一个视图", Toast.LENGTH_SHORT).show();
}else {
total--;
//清空内存
clearBitmap(listDate.get(now));
listDate.remove(now);
adapter.localNum = NowNum;
blackboardView1.updateView(NowNum-1);
}
}else if((now+1)==NowNum&&now!=0){
//向上移动
total--;
NowNum--;
clearBitmap(listDate.get(now));
listDate.remove(now);
adapter.localNum = NowNum;
blackboardView1.updateView(NowNum-1);
}else if((now+1)!=NowNum&&(now+1)>NowNum){
//不动
total--;
clearBitmap(listDate.get(now));
listDate.remove(now);
}else {
//整体上移
total--;
NowNum--;
clearBitmap(listDate.get(now));
listDate.remove(now);
adapter.localNum = NowNum;
blackboardView1.updateView(NowNum-1);
}
viewMember.tv_whereForNum.setText(numToString(NowNum)+"/"+numToString(total));
adapter.notifyDataSetChanged();
})
.setNegativeButton("取消",null).show();
break;
case 0x102://点击试图切换
now = msg.arg1;
NowNum = now+1;
adapter.localNum = NowNum;
//发送消息进行上传(目前感觉没必要上传)
//                        Message message = new Message();
//                        message.what = 16;
//                        message.arg1 = NowNum;
//                        System.out.println("popopopo nowNum:"+NowNum);
//                        //operateHandler
//同时更新的还有底部的数字
viewMember.tv_whereForNum.setText(numToString(NowNum)+"/"+numToString(total));
//                        oldBitmap = blackboardView1.cacheBitmap;
//                        operateHandler.sendEmptyMessage(100);//通知截屏上传(在没更新之前)
blackboardView1.updateView(NowNum-1);
adapter.notifyDataSetChanged();
break;
case 0x103://漫游:显示比例数值
viewMember.tv_zoomNum.setText(FTOString((Float) msg.obj));
break;
case 0x104://down的是时候不让获取获取焦点
viewMember.bt_tables.setEnabled(false);
viewMember.bt_last.setEnabled(false);
viewMember.bt_next.setEnabled(false);
viewMember.bt_add.setEnabled(false);
viewMember.tv_whereForNum.setEnabled(false);
Resources resources_table = mContext.getResources();
if (viewMember.lv_tables.getVisibility() == View.VISIBLE) {
viewMember.lv_tables.setVisibility(View.GONE);
viewMember.tv_whereForNum.setTextColor(Color.WHITE);
}
if(viewMember.ll_more.getVisibility()==View.VISIBLE){
viewMember.ll_more.setVisibility(View.GONE);
Drawable imageDrawable = resources_table.getDrawable(R.drawable.tables_uncheck);
viewMember.bt_tables.setBackground(imageDrawable);
}
//开始工具类的按钮
//1.首先要让下面一排子的东西点不了
viewMember.bt_pen.setEnabled(false);
viewMember.bt_eraser.setEnabled(false);
viewMember.bt_revoke.setEnabled(false);
viewMember.bt_recover.setEnabled(false);
viewMember.bt_zoom.setEnabled(false);
//2.布局恢复
if(viewMember.ll_penWidth.getVisibility() == View.VISIBLE){
//这个就证明在画笔的行列
viewMember.bt_width_1.setEnabled(false);
viewMember.bt_width_2.setEnabled(false);
viewMember.bt_width_3.setEnabled(false);
viewMember.bt_width_4.setEnabled(false);
viewMember.bt_width_5.setEnabled(false);
viewMember.bt_penColor.setEnabled(false);
if(viewMember.ll_colorAndAlpha.getVisibility() == View.VISIBLE){
viewMember.ll_colorAndAlpha.setVisibility(View.GONE);
}
}
if(viewMember.ll_eraser.getVisibility() == View.VISIBLE){
viewMember.bt_son_eraser.setEnabled(false);
viewMember.bt_handwriting_eraser.setEnabled(false);
viewMember.sb_clear_sliding.setEnabled(false);
}
break;
case 0x105://up的时候解封
viewMember.bt_tables.setEnabled(true);
viewMember.bt_last.setEnabled(true);
viewMember.bt_next.setEnabled(true);
viewMember.bt_add.setEnabled(true);
viewMember.tv_whereForNum.setEnabled(true);
viewMember.bt_pen.setEnabled(true);
viewMember.bt_eraser.setEnabled(true);
viewMember.bt_revoke.setEnabled(true);
viewMember.bt_recover.setEnabled(true);
viewMember.bt_zoom.setEnabled(true);
if(viewMember.ll_penWidth.getVisibility() == View.VISIBLE){
//这个就证明在画笔的行列
viewMember.bt_width_1.setEnabled(true);
viewMember.bt_width_2.setEnabled(true);
viewMember.bt_width_3.setEnabled(true);
viewMember.bt_width_4.setEnabled(true);
viewMember.bt_width_5.setEnabled(true);
viewMember.bt_penColor.setEnabled(true);
}
if(viewMember.ll_eraser.getVisibility() == View.VISIBLE){
viewMember.bt_son_eraser.setEnabled(true);
viewMember.bt_handwriting_eraser.setEnabled(true);
viewMember.sb_clear_sliding.setEnabled(true);
}
break;
case 0x106: //电子笔清除屏幕
new AlertDialog.Builder(mContext).setTitle("提示")
.setMessage("确定要清屏吗?")
.setPositiveButton("确定", (dialogInterface, i) -> {
blackboardView1.clear();
blackboardView1.isDialog = false;
})
.setNegativeButton("取消",(dialogInterface, i) -> {
blackboardView1.isDialog = false;
})
.show().setCanceledOnTouchOutside (false);
blackboardView1.clear_hardware();//清除其他笔画
}
super.handleMessage(msg);
}
};
}

Handler 涉及到了功能:这里涉及到后面要讲的功能,这里简单说下

  • 0x101 :当ListView点击删除时调用,弹出 AlertDialog 要求用户确定操作。

  • 0x102 :点击切换视图,主界面显示对应页的画布。

  • 0x103 :放大缩小时,显示比例数值。比如50% , 300%。

  • 0x104 :用户画线的时候,不允许操作ListView。

  • 0x105 :没有写画时允许操作。

  • 0x106:电子笔点击按钮后,调用清屏功能。

(4)更新画布 updateView

//切换视图,刷新
public void updateView(int whereView){
//对所有数据进行更新
ViewNum = whereView;
mPaintedList = mListDate.get(ViewNum).getPaintedList();
mCancelList = mListDate.get(ViewNum).getCancelList();
mRecoverList = mListDate.get(ViewNum).getRecoverList();
cacheBitmap = mListDate.get(ViewNum).getCacheBitmap();
cacheCanvas = mListDate.get(ViewNum).getCacheCanvas();
mMatrixMain = mListDate.get(ViewNum).matrixMain;
//传一下handler
mMatrixMain.getValues(mainDate);
Message m = this.handler.obtainMessage();
m.what = 0x103;
m.obj = mainDate[0];
this.handler.sendMessage(m);
cacheCanvas.drawColor(0,PorterDuff.Mode.CLEAR);
bottomCanvas.drawColor(0,PorterDuff.Mode.CLEAR);
invalidateReason = REASON_RE;
invalidate();
}

将 PictureView 中的对象赋值给当前视图即可。

二、PictureView中使用的实体类

这里具体介绍一下 PaintDates 和 MessageStrokes 具体内容。

(1)PaintDates.java

//保存每一笔的情况
//之后要实现笔锋效果(保存的就不是paint和path了)
public class PaintDates {
//没必要每次都new一个Paint:就透明的与width不同
Paint mPaint;
Path mPath; //专门为透明度服务
List mOnePaths ;
//保存每一笔画的偏移
ArrayList mMatrixS = new ArrayList<>();
//设置一个model来判断是这个类是点还是线(经历了move就是线,没有就是点)
private int lineModel = 1;//首先开始为点
final int POINT = 1;//点
final int LINE = 2 ;//线
final int DOTTED_LINE = 3;//虚线
//保存起点的x,y;
float mx;
float my;
float mXToMatrix;
float mYToMatrix;
//初始宽度(为点和虚线提供)
float mWidth;
//是否为待删除状态(为笔画删除提供服务)
private boolean isDelete = false;
private boolean isCut = false;
//设置一个与他同病相怜的兄弟集合(说白了保存id)
public boolean isCut() {
return isCut;
}
public void setCut(boolean cut) {
isCut = cut;
}
public boolean isDelete() {
return isDelete;
}
public void setDelete(boolean delete) {
isDelete = delete;
}
public PaintDates(Paint paint, List path, float x, float y,float width) {
mPaint = paint;
mOnePaths = path;
mx = x;
my = y;
mXToMatrix = x;
mYToMatrix = y;
mWidth = width;
}
public PaintDates(PaintDates pd){
mPaint = pd.mPaint;
mPath = pd.mPath;
mOnePaths = new ArrayList<>();
for (int i = 0; i  m/n + 1.
public void drawPlus(Canvas canvas){
Paint coverPaint = new Paint(mPaint);
int A = coverPaint.getAlpha();
coverPaint.setColor(Color.parseColor("#000000"));  //先暂时换个黑色
coverPaint.setAlpha(A);
if(lineModel == POINT){
//点的高光操作
coverPaint.setStrokeWidth(mWidth*2f);
canvas.drawPoint(mx,my,coverPaint);
}else if(lineModel == LINE){
for (PathAndWidth mPath:mOnePaths) {
coverPaint.setStrokeWidth(mPath.width*2f);
canvas.drawPath(mPath.path,coverPaint);
if(mPath.addPaths!=null){
for (int i = 0; i  addPaths;
//这个path已经无法满足需求
Float width ;
//形成path的后一个点
float x;
float y;
//此点的变形
float xToMatrix;
float yToMatrix;
//判断这个线是否要分割
boolean isCut = false;
//比例
float BL = -1;
public PathAndWidth(PathAndWidth paw){
if(paw.path!=null){
path = new Path(paw.path);
width = paw.width;
}
x = paw.x;
y = paw.y;
xToMatrix = paw.xToMatrix;
yToMatrix = paw.yToMatrix;
addPaths = paw.addPaths;
}
public PathAndWidth(Path path, Float width,float x,float y) {
this.path = path;
this.width = width;
this.x = x;
this.y = y;
//在没有zoom的情况下与原始点相同
xToMatrix = x;
yToMatrix = y;
}
//这是为透明度服务的
public PathAndWidth(float x,float y){
this.x = x;
this.y = y;
//在没有zoom的情况下与原始点相同
xToMatrix = x;
yToMatrix = y;
}
}
public int getLineModel() {
return lineModel;
}
public void setLineModel(int lineModel) {
this.lineModel = lineModel;
}
//颜色变化选项(后续有要求在搞)
}
//思路1:每两个点之间保存一段路径(性能要求非常高)
//思路2:保存点的信息化椭圆(需要保存一个方形)

核心成员变量及其作用:

变量名类型作用
mPaintPaint保存绘制这一笔时所用的画笔样式(颜色、透明度、抗锯齿等)
mOnePathsList<PathAndWidth>这是最关键的数据。它保存了构成这一笔的所有笔触段PathAndWidth 对象)。每个笔触段都包含一小段路径 (Path) 和绘制该段路径时动态变化的笔触宽度,以此来实现笔锋效果(压感、速度感应)。
mMatrixSArrayList<Matrix>保存这一笔画所经历过的所有变换矩阵(如平移、缩放、旋转)。这使得该笔画能够跟随画布进行变换,而自身的原始数据保持不变。
lineModelint标识这一笔的类型POINT (一个点)、LINE (一条连续的线)、DOTTED_LINE (一条虚线)。绘制和擦除逻辑会根据不同类型而变化。
mx, myfloat记录这一笔的起始点坐标。对于POINT类型,这就是点的位置;对于LINE,这是moveTo的起点。
mWidthfloat记录这一笔的初始(或基础)宽度。主要用于绘制POINTDOTTED_LINE,因为LINE的宽度由mOnePaths中的每个PathAndWidth动态管理。
isDeleteisCutboolean状态标志。用于实现笔画删除笔画分割功能。前面橡皮擦那章解释过

核心方法及其作用:

方法名作用
draw(Canvas canvas)核心绘制方法。根据lineModel调用对应的绘制方法(drawPointdrawLinedrawDottedLine),将这一笔画到传入的Canvas上。
drawPlus(Canvas canvas)绘制包裹高光效果。通常用于实现笔画选中状态。它会用原笔画两倍的宽度和特定颜色(代码中为黑色)再画一遍,形成“包裹”或“高亮”效果,提示用户该笔画被选中。
drawDottingRed(Canvas canvas, float p)绘制虚线效果。用于橡皮擦功能。当用户使用橡皮擦时,可能用红色的虚线来预览即将被擦除的笔画区域。参数p用于控制虚线模式的偏移,实现动画效果。
drawPatch(Canvas canvas)仅绘制最后一小段路径。用于实时绘制(即用户手指还在移动时)。为了提高性能,在用户快速绘画时,不需要重绘整个复杂路径,只需绘制最新的一小段(mOnePaths的最后一个元素)。
drawFrontAddPath(...)绘制前一段路径的笔锋。这是一个更细粒度的优化,用于确保在连续绘制时,笔锋的衔接部分也能被正确绘制,避免出现断点。

PathAndWidth (路径与宽度)

这是一个内部静态类,是 PaintDates 的组成部分。它可以被称为笔触段数据持有者。它的存在是实现笔锋效果的关键。

核心成员变量及其作用:

变量名类型作用
pathPath保存一小段贝塞尔曲线路径(由 quadTo生成)。
widthFloat保存绘制这一小段路径时所用的笔触宽度。笔锋效果就是通过路径不断变化的同时,宽度也随之变化(模拟压感)来实现的。
addPathsArrayList<Path>附加路径。为了实现笔锋效果,前几章有介绍
x, yfloat记录这一小段路径的终点坐标
xToMatrix, yToMatrixfloat记录经过变换矩阵作用后,终点坐标应该所在的位置。用于坐标转换计算。
isCutboolean标识此笔触段是否处于被分割的状态。

(2)MessageStrokes.java

//负责保存每一个操作
public class MessageStrokes {
int MassageType;  //信息种类
ArrayList paintStrokes;//保存每个笔画的
Matrix matrix;
Matrix mainMatrix;//用于保存右侧的数字
public MessageStrokes(int massageType) {
MassageType = massageType;
}
static class IdAndStrokes{
int id ;
int num ;//针对于橡皮擦单独设置,用来判断需要删除此ID几次。
PaintDates pd ;
public IdAndStrokes(int id,PaintDates pd) {
this.id = id;
this.pd = pd;
}
}
}
//对于笔画删除而言,一定是倒着删除。所以恢复的时候一定是正着来(id+笔画)

这个类的主要作用是:封装并保存一个完整的用户操作,用于实现撤销 (Undo) 和重做 (Redo) 功能,后面介绍撤销恢复时详细说明。本章节篇幅较少,主要是介绍多画布的框架,为后面的章节打好基础。

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

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

相关文章

ESP32 读取旋转编码器

1、旋转编码器原理1.1、以A输入为时钟,边沿中断检测A输入的上升边沿,同时在中断回调函数判断B的电平状态 ①正转CW:A上升沿,B低电平; ②反转CWW:A上升沿,B高电平; 1.2、中间按键直接使用电平或者电平中断检测;…

负载分析和排查六

负载分析和排查六明白,我帮你整理成一个完整专业文档,覆盖 CPU 各类负载(%user、%sys、%soft、%si、%iowait)分析、溯源、定位工具与优化策略,并包含脚本示例和中断原理说明。文档结构清晰,便于直接使用或汇报。…

赣州市建设工程造价管理网站现在做百度推广有用吗

目录 3.3 网络结构与损失函数设计 3.3.1 网络结构 3.3.2 损失函数设计

js网站大全郑州网站制作推广

除了基本的分组功能之外&#xff0c;GROUP BY 子句还提供了几个高级选项&#xff0c;可以用来实现更复杂的报表功能。 本文比较五种主流数据库实现的高级分组功能&#xff0c;包括 MySQL、Oracle、SQL Server、PostgreSQL 以及 SQLite。 功能MySQLOracleSQL ServerPostgreSQL…

苏州高端网站设计企业西安网络科技有限公司有哪些

1. 引言 限界上下文可以拆分为两个词&#xff0c;限界和上下文。限界&#xff1a;是指一个界限&#xff0c;具体的某一个范围。上下文&#xff1a;个人理解就是语境。 比如我们常说的段子&#xff1a; “我想静静。”这个句子一般是想表达“我想静一静”的意思。但是我们却把…

网站内容建设要求 age06建设六马路小学 网站

此文为人大金仓数据库安装程序&#xff08;windows下kingbase开发及测试用&#xff09;。 1 人大金仓-成为世界卓越的数据库产品与服务提供商 官方下载安装包&#xff0c;同时需要下载授权文件&#xff0c;补丁文件可以不下。 2 点击安装 3 选择授权文件 4 默认安装即可&…

饰品交易网站怎么做做礼品建什么网站

Kafka消费流程 消息是如何被消费者消费掉的。其中最核心的有以下内容。 1、多线程安全问题 2、群组协调 3、分区再均衡 1.多线程安全问题 当多个线程访问某个类时&#xff0c;这个类始终都能表现出正确的行为&#xff0c;那么就称这个类是线程安全的。 对于线程安全&…

武威市建设局网站 放管服网站服务公司业务范围包括

软件项目范围基准明确了项目的边界、目标和主要交付成果&#xff0c;有助于提高项目成本、进度和资源估算的准确性&#xff0c;便于实施项目控制&#xff0c;而且还可以帮助我们清楚分派责任&#xff0c;防止范围蔓延&#xff0c;从而提升项目的成功率。 如果没有明确确定范围基…

网站建设php的心得和体会动漫设计网站

建议将全局变量创建在.h/.cpp文件中&#xff0c;其中.h文件声明变量&#xff0c;.cpp文件中定义变量值。 在.h文件中定义变量&#xff0c;则工程多次#include该文件会出现“该文件已经被使用”。 具体示例如下&#xff1a; synchronize_data.h // // Created by qiaowei on…

大地资源影视免费观看淄博网站建设优化运营熊掌号

介绍 Nginx是一个高性能的Web服务器&#xff0c;它可以处理大量的并发请求&#xff0c;同时还可以作为负载均衡器和反向代理服务器。在本篇博文中&#xff0c;我们将介绍如何从入门到精通Nginx的使用。 Nginx的安装和配置 在开始使用Nginx之前&#xff0c;您需要先安装和配置…

mysql/oracle LEFT JOIN 取时间最大的数据

如下SQL ,一次任务执行结果 没有聚合到任务结果表,可以在任务结果表中查询出这个任务结果id,然后可根据任务结果id内存遍历或者通过not exists进行结果明细的成功失败查询。select t.task_id,t.task_name, maxr.tas…

6月6日证书 - 工信部人才交流中心PostgreSQL中级PGCP高级PGCM认证

恭喜上一期参加并通过工信部人才交流中心PostgreSQL管理员PG中级和PG高级认证考试的各位同学,纸质版证书到啦【9月16日】! 电子版证书可以在工信部人才交流中心官网查询,或者联系CUUG客服!工信部人才交流中心Postgr…

基于遗传算法与非线性规划的混合优化算法在电力系统最优潮流中的实现

基于遗传算法(GA)与非线性规划(NLP)的混合优化算法在电力系统最优潮流(OPF)中的实现一、混合算法架构设计 混合策略优势全局探索:GA处理非凸、多峰问题,避免陷入局部最优 局部开发:NLP(如内点法)加速收敛,…

【下一款产品】

从哪里获取灵感、如何判断价值、最后怎么选。 ⸻ 1️⃣ 灵感来源(参考哪些网站) 🔹 全球趋势/新产品 • Product Hunt → 每天看独立开发者和公司在推什么工具,评论区也能看到用户需求。 • Hacker News → 技术社…

数1的个数

//题意:给定一个十进制正整数n,写下从1到n的所有整数,然后数一下其中出现的数字“1”的个数。 //例如当n=2时,写下1,2。这样只出现了1个“1”;当n=12时,写下1,2,3,4,5,6,7,8,9,10,11,12。这样出现了5…

企业网站快速建站深圳网站搭建找谁

一、pytest跳过功能 1. 使用 pytest.skip 装饰器跳过测试用例 Pytest中的 pytest.skip 装饰器允许你跳过指定的测试用例。你可以将该装饰器应用于测试函数或测试类上。 import pytestpytest.mark.skip(reason"Skipping this test case") def test_skip():assert 1…

青州网站建设优化推广wordpress 网站图标设置

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于Kronig-Penney能带模型的MATLAB求解与仿真.综合利用 MATLAB提供的求解常微分方程、矩阵行列式、代数表达式化简及绘图等函数 ,可使 Kronig-Penney能带模型分析…

有没有做门面设计的网站网站备案掉了怎么办

烘焙预计算 前文:续_直接和间接光照这一篇小结:Unity烘焙预计算烘焙前的场景设置1.2.Contribute GI如下图:物体的Static和面板上的Contribute GILightmap的UV模型自带Lightmap的UVUnity 自动展Lightmap的UV1.3.Meta PassMeta Pass代码如下:1.4.Light Mode模式

做外贸都做哪些网站好免费下载网站开发国内外研究状况

感谢使用护卫神云查杀系统&#xff0c;该软件专门查杀网页木马&#xff0c;完全免费&#xff0c;欢迎大家使用。远程FTP查杀部分&#xff1a;1、点击【远程查杀】图标&#xff0c;如上图所示&#xff0c;进入远程FTP查杀页面&#xff1a;1、首先要求输入远程FTP连接信息&#x…

网站域名注册管理中心书店商城网站设计

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 stack容器queue容器 stack容器 是什么&#xff1f;功能是什么&#xff1f;常用接口是什么&#xff1f;局限性有哪些&#xff1f;优势又有哪些&#xff1f; 栈容器&#xff0c;先进…