javafx实现图片缩放和拖动

news2025/1/8 5:05:25

目录

  • 前言
  • 方式一
  • 方式二
    • 1.带有滚动条的缩放
      • (1)代码
      • (2)效果
    • 2.fxml 布局+java代码
      • (1) fxml 布局文件
      • (2) java 代码
      • (3) 效果

前言

本文使用的是 jdk8 的 javafx 运行实现的图片缩放操作效果。

方式一

通过改变 ImageView 的 FitHeight、FitWidth 来改变及调整长宽来缩放,你可以参考这篇文章JavaFX图片浏览并实现缩放

fxml文件里ImageView如下:

<ImageView fx:id="image" fitHeight="600.0" fitWidth="600.0" pickOnBounds="true" preserveRatio="true" />

java代码如下:

     static double size = 1;
     static double count = 1.0;
    
     //鼠标滚轮控制图片缩放
     image.setOnScroll(event -> {
            // 缩放具体逻辑
            if (event.getDeltaY() > 0) {
                // 这里是向上滚动滚轮(即放大图片)
                count = count + 1.0 / 10;
                size = 1.0 / 200 * (count - 1) * (count - 1) * (count - 1) + 1;
                image.setFitWidth(image.getFitWidth() * size);
                image.setFitHeight(image.getFitHeight() * size);
                count++;
            } else {
                // 这里是乡下滚动滚轮(即缩小图片)
                count = count - 1.0 / 10;
                double y = 1.0 / 200 * (count - 1) * (count - 1) * (count - 1) + 1;
                size = y < 0 ? size : y;
                image.setFitWidth(image.getFitWidth() / size);
                image.setFitHeight(image.getFitHeight() / size);
                count--;
            }
     });

方式二

上面的方式确实能够实现鼠标滚轮进行图片缩放,但它缩放时 ImageView 所在的整个 stage 页面也会缩放。
那怎么让图片在一个框里缩放呢,也就是让图片只在指定框的区域显示并缩放,你可以使用 ImageView 里的 setViewport 方法并在里面使用 Rectangle2D 设置图形的位置和宽高,
你可以参考这篇文章:Zooming an Image in ImageView (javafx)

1.带有滚动条的缩放

(1)代码

你可以直接复制如下代码,运行便可看到效果(使用jdk8)


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javafx.application.Application;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class MainServer extends Application {
    static double initx;
    static double inity;
    static int height;
    static int width;
    public static String path;
    static Scene initialScene, View;
    static double offSetX, offSetY, zoomlvl;

    @Override
    public void start(Stage s) {
        s.setResizable(false);
        GridPane grid = new GridPane();
        grid.setHgap(20);
        grid.setVgap(20);
        grid.setAlignment(Pos.CENTER);

        Label hint = new Label("你选择的图片:");
        TextField URL = new TextField();
        URL.setEditable(false);
        URL.setPrefWidth(350);

        Button browse = new Button("选择图片");
        //现在只能选择jpg、png格式的图片
        FileChooser fc = new FileChooser();
        ExtensionFilter png = new ExtensionFilter("png", "*.png");
        ExtensionFilter jpg = new ExtensionFilter("jpg", "*.jpg");
        fc.getExtensionFilters().addAll(jpg,png);
        //点击选择图片按钮的事件
        browse.setOnAction(e -> {
            URL.setText(fc.showOpenDialog(s).getAbsolutePath());
        });

        Button open = new Button("打开");
        //点击打开按钮的事件
        open.setOnAction(e -> {
            //获取图片路径到
            path = URL.getText();
            //初始化显示图片
            initView();
            s.setScene(View);
        });

        grid.add(hint, 0, 0);
        grid.add(URL, 1, 0);
        grid.add(browse, 2, 0);
        grid.add(open, 2, 1);

        initialScene = new Scene(grid, 600, 100);
        s.setScene(initialScene);
        s.show();
    }

    public static void initView() {
        VBox root = new VBox(20);
        root.setAlignment(Pos.CENTER);

        Label title = new Label(path.substring(path.lastIndexOf("\\") + 1));
        //加载图片
        Image source = null;
        try {
            source = new Image(new FileInputStream(path));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        ImageView image = new ImageView(source);
        //获取图片长宽比
        double ratio = source.getWidth() / source.getHeight();
        //设置长宽
        if (500 / ratio < 500) {
            width = 500;
            height = (int) (500 / ratio);
        } else if (500 * ratio < 500) {
            height = 500;
            width = (int) (500 * ratio);
        } else {
            height = 500;
            width = 500;
        }
        //设置图片长宽
        image.setPreserveRatio(false);
        image.setFitWidth(width);
        image.setFitHeight(height);
        height = (int) source.getHeight();
        width = (int) source.getWidth();
        System.out.println("height = " + height + "\nwidth = " + width);

        //设置底部缩放滑动条,缩放程度限制为1到4
        HBox zoom = new HBox(10);
        zoom.setAlignment(Pos.CENTER);
        Slider zoomLvl = new Slider();
        zoomLvl.setMax(4);
        zoomLvl.setMin(1);
        zoomLvl.setMaxWidth(200);
        zoomLvl.setMinWidth(200);
        Label hint = new Label("缩放程度");
        Label value = new Label("1.0");
        zoom.getChildren().addAll(hint, zoomLvl, value);

        offSetX = width / 2;
        offSetY = height / 2;

        //设置顶部水平拖动滑动条
        Slider Hscroll = new Slider();
        Hscroll.setMin(0);
        Hscroll.setMax(width);
        Hscroll.setMaxWidth(image.getFitWidth());
        Hscroll.setMinWidth(image.getFitWidth());
        Hscroll.setTranslateY(-20);
        //设置右侧垂直拖动滑动条
        Slider Vscroll = new Slider();
        Vscroll.setMin(0);
        Vscroll.setMax(height);
        Vscroll.setMaxHeight(image.getFitHeight());
        Vscroll.setMinHeight(image.getFitHeight());
        Vscroll.setOrientation(Orientation.VERTICAL);
        Vscroll.setTranslateX(-20);

        //将三个滑动条和图片放到 imageView 布局上
        BorderPane imageView = new BorderPane();
        BorderPane.setAlignment(Hscroll, Pos.CENTER);
        BorderPane.setAlignment(Vscroll, Pos.CENTER_LEFT);
        imageView.setCenter(image);
        imageView.setTop(Hscroll);
        imageView.setRight(Vscroll);
        //设置鼠标手张开的图标
        imageView.setCursor(Cursor.OPEN_HAND);
        //顶部滑动条变化时的出发事件
        Hscroll.valueProperty().addListener(e -> {
            offSetX = Hscroll.getValue();
            zoomlvl = zoomLvl.getValue();
            double newValue = (double) ((int) (zoomlvl * 10)) / 10;
            value.setText(newValue + "");
            if (offSetX < (width / newValue) / 2) {
                offSetX = (width / newValue) / 2;
            }
            if (offSetX > width - ((width / newValue) / 2)) {
                offSetX = width - ((width / newValue) / 2);
            }
            image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
        });
        //右侧滑动条变化时的出发事件
        Vscroll.valueProperty().addListener(e -> {
            offSetY = height - Vscroll.getValue();
            zoomlvl = zoomLvl.getValue();
            double newValue = (double) ((int) (zoomlvl * 10)) / 10;
            value.setText(newValue + "");
            if (offSetY < (height / newValue) / 2) {
                offSetY = (height / newValue) / 2;
            }
            if (offSetY > height - ((height / newValue) / 2)) {
                offSetY = height - ((height / newValue) / 2);
            }
            image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
        });
        //底部滑动条变化时的出发事件
        zoomLvl.valueProperty().addListener(e -> {
            zoomlvl = zoomLvl.getValue();
            double newValue = (double) ((int) (zoomlvl * 10)) / 10;
            value.setText(newValue + "");
            if (offSetX < (width / newValue) / 2) {
                offSetX = (width / newValue) / 2;
            }
            if (offSetX > width - ((width / newValue) / 2)) {
                offSetX = width - ((width / newValue) / 2);
            }
            if (offSetY < (height / newValue) / 2) {
                offSetY = (height / newValue) / 2;
            }
            if (offSetY > height - ((height / newValue) / 2)) {
                offSetY = height - ((height / newValue) / 2);
            }
            Hscroll.setValue(offSetX);
            Vscroll.setValue(height - offSetY);
            image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
        });
        //鼠标在图片上按压的事件
        image.setOnMousePressed(e -> {
            initx = e.getSceneX();
            inity = e.getSceneY();
            imageView.setCursor(Cursor.CLOSED_HAND);
        });
        //鼠标在图片上松开的事件
        image.setOnMouseReleased(e -> {
            imageView.setCursor(Cursor.OPEN_HAND);
        });
        //鼠标在图片上拖动的事件
        image.setOnMouseDragged(e -> {
            Hscroll.setValue(Hscroll.getValue() + (initx - e.getSceneX()));
            Vscroll.setValue(Vscroll.getValue() - (inity - e.getSceneY()));
            initx = e.getSceneX();
            inity = e.getSceneY();
        });
        //鼠标在图片上滚轮滚动控制缩放的事件。缩放程度限制在1到4,每次滚动缩放0.3
        image.setOnScroll(event -> {
            zoomlvl = zoomLvl.getValue();
            if (event.getDeltaY() > 0) {
                if (zoomlvl < 4) {
                    zoomLvl.setValue(zoomlvl + 0.3);
                }
            } else {
                if (zoomlvl > 1) {
                    zoomLvl.setValue(zoomlvl - 0.3);
                }
            }
        });
        root.getChildren().addAll(title, imageView, zoom);
        //设置新窗口的大小
        View = new Scene(root, (image.getFitWidth()) + 90, (image.getFitHeight()) + 170);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

(2)效果

请添加图片描述

请添加图片描述

2.fxml 布局+java代码

上面的示例是纯使用java来布局并控制逻辑的,并且还带有滑动条。下面调整下使用 fxml 进行布局,用java代码控制逻辑,并隐藏所有滑动条。

你可以参考我下面的写法,如你想运行或查看完整的本示例项目,你可以看我: github的XTool项目地址

(1) fxml 布局文件

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.*?>
<?import com.jfoenix.controls.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.ImageView?>

<StackPane fx:id="root" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
    <children>
        <VBox  maxHeight="1050" maxWidth="1200" spacing="30" >
            <children>
                <HBox spacing="20" alignment="BASELINE_LEFT" style="-fx-padding:130 0 0 0 ">
                    <children>
                        <JFXButton fx:id="fileButton" layoutX="55.0"  style="-fx-background-color: #5cb85c;" text="打开图片" textFill="WHITE"  />
                        <JFXButton fx:id="identify" layoutX="170.0" layoutY="204.0" style="-fx-background-color: #5cb85c;" text="识别" textFill="WHITE" />
                        <JFXButton fx:id="copy" layoutX="199.0" layoutY="204.0" style="-fx-background-color: #5cb85c;" text="复制结果" textFill="WHITE" />
                        <JFXButton fx:id="clear" layoutX="219.0" layoutY="204.0" style="-fx-background-color: #c9302c;" text=" 清空 " textFill="WHITE" />
                    </children>
                </HBox>

                <HBox spacing="20"  maxHeight="550" prefHeight="550" >
                    <children>

                        <SplitPane layoutX="55.0" layoutY="14.0" prefHeight="550.0" prefWidth="700.0" maxHeight="550" style="-fx-padding:10 10 -400 50;-fx-font: 15 arial;" >
                            <VBox  maxHeight="550"  prefHeight="550" style="-fx-padding:0 10 0 40">
                                <children>
                                    <!-- 使用  visible="false" 隐藏顶部滚动条-->
                                    <Slider fx:id="Hscroll"  min="0" translateY="-20" maxHeight="0" maxWidth="0" visible="false"></Slider>
                                    <ImageView fx:id="image"  pickOnBounds="true" preserveRatio="false" />
                                    <!-- 使用  visible="false" 隐藏底部滚动条 使用 maxWidth="0" 让宽度设为0也为了不显示-->
                                    <Slider fx:id="zoomLvl" maxWidth="0"  max="6" min="1" visible="false"></Slider>
                                    <!-- 使用  visible="false" 隐藏底部滚动条的名称 使用 maxHeight、maxWidth 让长宽为0也为了不显示-->
                                    <Label fx:id="hint"  maxHeight="0" maxWidth="0" visible="false">缩放程度</Label>
                                    <!-- 使用  visible="false" 隐藏右侧滚动条 使用 maxHeight、maxWidth 让长宽为0也为了不显示-->
                                    <Slider fx:id="Vscroll" min="0" translateX="-20" orientation="VERTICAL"  maxHeight="0" maxWidth="0" visible="false"></Slider>
                                    <!-- 使用  visible="false" 隐藏底部滚动条的值 使用 maxHeight、maxWidth 让长宽为0也为了不显示-->
                                    <Label fx:id="value"  maxHeight="0" maxWidth="0" visible="false">1.0</Label>
                                </children>
                            </VBox>
                        </SplitPane>

                        <TextArea fx:id="resultArea" layoutX="55.0" layoutY="238.0" prefHeight="550.0" prefWidth="700.0" promptText="识别结果(仅支持识别中英文)" style="-fx-padding: 5 5 5 5;-fx-font: 15 arial;" >
                            <opaqueInsets>
                                <Insets />
                            </opaqueInsets>
                        </TextArea>
                    </children>
                </HBox>

            </children>
        </VBox>
    </children>
</StackPane>


(2) java 代码

import com.jfoenix.controls.JFXButton;
import io.datafx.controller.ViewController;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.control.TextArea;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.BorderPane;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;

@ViewController(value = "/fxml/ui/Ocr.fxml", title = "OCR图片识字")
public class OcrController {
    @FXML
    private JFXButton fileButton;
    @FXML
    private JFXButton identify;
    @FXML
    private JFXButton copy;
    @FXML
    private JFXButton clear;
    @FXML
    private TextArea borderArea;
    @FXML
    private ImageView image;
    @FXML
    private TextArea resultArea;
    @FXML
    private Slider Hscroll;
    @FXML
    private Label hint;
    @FXML
    private Slider zoomLvl;
    @FXML
    private Label value;
    @FXML
    private Slider Vscroll;

    private static double size = 1;
    private static double count = 1.0;
    private String imagePath = "";//图像路径
    private static int width = 0;
    static int height = 0;
    static double ratio = 0;
    private Image source = null;
    private static double offSetX, offSetY, zoomlvl;
    private static double initx;
    private static double inity;

    @PostConstruct
    public void init() {
        //选择文件按钮
        fileButton.setOnAction(action -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("选择图像文件");
            File file = fileChooser.showOpenDialog(new Stage());
            if (file != null) {
                //获取图像路径
                imagePath = file.getAbsolutePath();
                System.out.println(imagePath);
                FileInputStream input = null;
                try {
                    input = new FileInputStream(imagePath);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                //获取图像为Image对象
                source = new Image(input);
                //获取长宽比
                getWidthHeight();
                //设置图像的长宽和设置到ImageView对象
                image.setImage(source);
                image.setPreserveRatio(false);
                image.setFitWidth(width);
                image.setFitHeight(height);
                height = (int) source.getHeight();
                width = (int) source.getWidth();

                offSetX = width / 2;
                offSetY = height / 2;
                //设置顶部滚动条
                Hscroll.setMax(width);
                Hscroll.setMaxWidth(image.getFitWidth());
                Hscroll.setMinWidth(image.getFitWidth());
                //设置右侧滚动条
                Vscroll.setMax(height);
                Vscroll.setMaxHeight(image.getFitHeight());
                Vscroll.setMinHeight(image.getFitHeight());
                BorderPane.setAlignment(Hscroll, Pos.CENTER);
                BorderPane.setAlignment(Vscroll, Pos.CENTER_LEFT);
                //顶部滚动条监听
                Hscroll.valueProperty().addListener(e -> {
                    offSetX = Hscroll.getValue();
                    zoomlvl = zoomLvl.getValue();
                    double newValue = (double) ((int) (zoomlvl * 10)) / 10;
                    value.setText(newValue + "");
                    if (offSetX < (width / newValue) / 2) {
                        offSetX = (width / newValue) / 2;
                    }
                    if (offSetX > width - ((width / newValue) / 2)) {
                        offSetX = width - ((width / newValue) / 2);
                    }

                    image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
                });
                //右侧滚动条监听
                Vscroll.valueProperty().addListener(e -> {
                    offSetY = height - Vscroll.getValue();
                    zoomlvl = zoomLvl.getValue();
                    double newValue = (double) ((int) (zoomlvl * 10)) / 10;
                    value.setText(newValue + "");
                    if (offSetY < (height / newValue) / 2) {
                        offSetY = (height / newValue) / 2;
                    }
                    if (offSetY > height - ((height / newValue) / 2)) {
                        offSetY = height - ((height / newValue) / 2);
                    }

                    image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
                });
                //底部缩放滚动条监听
                zoomLvl.valueProperty().addListener(e -> {
                    zoomlvl = zoomLvl.getValue();
                    double newValue = (double) ((int) (zoomlvl * 10)) / 10;
                    value.setText(newValue + "");
                    if (offSetX < (width / newValue) / 2) {
                        offSetX = (width / newValue) / 2;
                    }
                    if (offSetX > width - ((width / newValue) / 2)) {
                        offSetX = width - ((width / newValue) / 2);
                    }
                    if (offSetY < (height / newValue) / 2) {
                        offSetY = (height / newValue) / 2;
                    }
                    if (offSetY > height - ((height / newValue) / 2)) {
                        offSetY = height - ((height / newValue) / 2);
                    }
                    Hscroll.setValue(offSetX);
                    Vscroll.setValue(height - offSetY);
                    image.setViewport(new Rectangle2D(offSetX - ((width / newValue) / 2), offSetY - ((height / newValue) / 2), width / newValue, height / newValue));
                });
                //鼠标在图片上按压的事件
                image.setOnMousePressed(e -> {
                    initx = e.getSceneX();
                    inity = e.getSceneY();
                    image.setCursor(Cursor.CLOSED_HAND);
                });
                //鼠标在图片上松开的事件
                image.setOnMouseReleased(e -> {
                    image.setCursor(Cursor.OPEN_HAND);
                });
                //鼠标在图片上拖动的事件
                image.setOnMouseDragged(e -> {
                    Hscroll.setValue(Hscroll.getValue() + (initx - e.getSceneX()));
                    Vscroll.setValue(Vscroll.getValue() - (inity - e.getSceneY()));
                    initx = e.getSceneX();
                    inity = e.getSceneY();
                });
            }
        });

        //鼠标图片缩放控制
        image.setOnScroll(event -> {
            zoomlvl = zoomLvl.getValue();
            if (event.getDeltaY() > 0) {
                if (zoomlvl < 6) {
                    zoomLvl.setValue(zoomlvl + 0.3);
                }
            } else {
                if (zoomlvl > 1) {
                    zoomLvl.setValue(zoomlvl - 0.3);
                }
            }
        });

        //识别按钮
        identify.setOnAction(action -> {
            if (imagePath.length() == 0) {
                return;
            }
            long start = System.currentTimeMillis();
            //加载要识别的图片
            File image = new File(imagePath);
            //设置配置文件夹微视、识别语言、识别模式
            Tesseract tesseract = new Tesseract();
            tesseract.setDatapath("src/main/resources/tessdata");
            tesseract.setLanguage("chi_sim");
            tesseract.setPageSegMode(1);
            //设置引擎模式
            tesseract.setOcrEngineMode(1);
            //开始识别图片中的文字
            String result = null;
            try {
                result = tesseract.doOCR(image);
            } catch (TesseractException e) {
                e.printStackTrace();
            }
            long time = System.currentTimeMillis() - start;
            System.out.println("识别结束,耗时:" + time + " 毫秒,识别结果如下:");
            System.out.println();
            System.out.println(result);
            resultArea.setText(result);
        });

        //复制按钮事件
        copy.setOnAction(action -> {
            String str = resultArea.getText();
            Clipboard clipboard = Clipboard.getSystemClipboard();
            ClipboardContent content = new ClipboardContent();
            content.putString(str);
            clipboard.setContent(content);
        });

        //清除按钮事件
        clear.setOnAction(action -> {
            source = null;
            image.setImage(null);
            imagePath = "";
            ratio = 0;
            width = 0;
            height = 0;
            resultArea.setText("");
            zoomlvl = 1;
            initx = 0;
            inity = 0;
            zoomLvl.setValue(1);
        });
    }

    //获取长宽、长宽比
    private void getWidthHeight() {
        width = (int) source.getWidth();
        height = (int) source.getHeight();
        ratio = source.getWidth() / source.getHeight();//获取长宽比
        if (500 / ratio < 500) {
            width = 500;
            height = (int) (500 / ratio);
        } else if (500 * ratio < 500) {
            height = 500;
            width = (int) (500 * ratio);
        } else {
            height = 500;
            width = 500;
        }
    }
}

(3) 效果

请添加图片描述


参考:
JavaFX图片浏览并实现缩放
Zooming an Image in ImageView (javafx)

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

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

相关文章

element 日期选择器下拉框被覆盖

解决&#xff1a;在对应下拉框el-select 标签 添加calss属性即可。此方法不仅适用于日期下拉框&#xff0c;适用于所有下拉框 class"dropdownbox" .dropdownbox{ z-index: 10001 !important; } 图片来自&#xff1a;element ui 时间筛选样式遮盖问题修复_代码搬运媛…

Jmeter接口测试:jmeter导入和导出接口的处理

JMeter测试导入接口 利用Jmeter测试上传文件&#xff0c;首先可根据接口文档或者fiddler抓包分析文件上传的接口&#xff1b;如下图&#xff1a; 以下是我通过fiddler所截取的文件上传的接口 1、填写导入接口的信息 查看文件上传栏下的填写信息&#xff1a; 文件名称&#x…

【STM32】软件I2C控制频率

在上一篇文章中&#xff0c;我们已经介绍了整个软件I2C的实现原理&#xff0c;但是也遗留了一个问题&#xff0c;那就是I2C速率的控制&#xff0c;其实就是控制SCL信号的频率。 微秒级延时 在上篇文章中&#xff0c;我们使用了SysTick进行延时&#xff0c;具体如下&#xff1…

分析生态系统服务社会价值问题

生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xff0c;对提升人类福祉具有重大意义&#xff0c;且被视为连接社会与生态系统的桥梁。自从启动千年生态系统评估项目&#xff08;Millennium Ecosystem Asse…

飞致云开源社区月度动态报告(2023年6月)

自2023年6月起&#xff0c;中国领先的开源软件公司FIT2CLOUD飞致云将以月度为单位发布《飞致云开源社区月度动态报告》&#xff0c;旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况&#xff0c;以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源大…

准备项目管理软考前,这份备考经验你不得不看

早上好&#xff0c;我是老原。 5月的全国计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试 &#xff08;简称软考&#xff09;的考试即将开始&#xff0c;不知道大家都准备的如何&#xff1f; 虽然5月考试的报名时间已经过了&#xff0c;但还是有新一波粉丝朋友…

解决微信后台禁用url问题

解决微信后台禁用url问题 由于目前用的平台&#xff0c;域名都没有在微信授权&#xff0c;所以被微信给禁用了&#xff0c;我们现在用一个接口可以绑定域名的平台转发一下&#xff0c;演示选择使用vscode工具&#xff0c;其它有终端的工具亦可。 1. 安装vercel 全局安装verce…

虹科分享|如何防范MOVEit transfer漏洞|高级威胁防御

美国网络安全和基础设施安全局(CISA)承认&#xff0c;它正在向几个联邦机构提供支持&#xff0c;这些机构在Progress(前身为IpSwitch)MOVEit传输解决方案中暴露出漏洞后被攻破。根据CISA发布的一份警报和网络安全公告&#xff0c;CL0P勒索软件团伙一直在积极利用漏洞进行数据外…

SpringBoot + Druid监控 MySQL,慢SQL快速定位,真好用!

我们都使用过连接池&#xff0c;比如C3P0&#xff0c;DBCP&#xff0c;hikari&#xff0c; Druid&#xff0c;虽然HikariCP的速度稍快&#xff0c;但Druid能够提供强大的监控和扩展功能&#xff0c;也是阿里巴巴的开源项目。 Druid是阿里巴巴开发的号称为监控而生的数据库连接…

环肽抑制剂:244082-19-7,CTTHWGFTLC, CYCLIC,属于基质金属蛋白酶 MMP-2 和 MMP-9

文章编辑来自于&#xff1a;陕西新研博美生物科技有限公司MISS.wu​ CTTHWGFTLC, CYCLIC | CAS&#xff1a;244082-19-7| 纯度&#xff1a;95% 结构式&#xff1a; 试剂参数信息&#xff1a; CAS&#xff1a;244082-19-7 外观&#xff08;Appearance&#xff09;&#xff1…

fastadmin框架select下拉框该怎么写(接口数据)

先让大家看一下最终效果&#xff1a; 来上代码&#xff1a; <select id"c-education" data-rule"required" class"form-control selectpicker" name"row[education]">{foreach name"education" item"vo"}&…

【Linux | Shell命令】bash shell 进程、磁盘、文件处理命令

目录 &#x1f384;一、概述&#x1f384;二、进程相关命令✨2.1 ps 命令 —— 查看进程✨2.2 top 命令 —— 实时监测进程✨2.3 kill、pkill 命令 —— 结束进程 &#x1f384;三、磁盘相关命令✨3.1 mount、umount 命令 —— 挂载、卸载命令✨3.2 df 命令 —— 查看磁盘空间✨…

DCompute链下计算外包:只EVM就足够了么?

1. 引言 当前的以太坊L2扩容方案主要有&#xff1a; Optimistic RollupzkRollup&#xff1a;如Polygon zkEVM、Scroll等 这些L2方案仍是基于EVM的。 但游戏、链上订单簿、Web3社交、机器学习、基因组建模等高性能应用是compute-heavy的&#xff0c;对于L2 EVM来说仍是昂贵的…

深入理解 Golang: Goroutine 协程

进程用来分配内存空间&#xff0c;是操作系统分配资源的最小单位&#xff1b;线程用来分配 CPU 时间&#xff0c;多个线程共享内存空间&#xff0c;是操作系统或 CPU 调度的最小单位&#xff1b;协程用来精细利用线程。协程就是将一段程序的运行状态打包&#xff0c;可以在线程…

idea连接MYSQL报错汇总

idea连接MYSQL报错汇总 【The last packet sent successfully to the server was 0 milliseconds ago.The driver has not received any packets from the server.】 原因&#xff1a;mysql57 运行在非默认端口号 解决&#xff1a; 1.测试本地连接mysqsl57 打开C:\ProgramDa…

管理类联考——数学——技巧篇——公式——函数、方程与不等式

集合 A 有 n 个元素&#xff0c;则集合 A 的子集个数为 2 n 2^n 2n个&#xff0c;真子集个数为 2 n − 1 2^n-1 2n−1个&#xff0c;非空子集个数为 2 n − 1 2^n-1 2n−1个&#xff0c;非空真子集个数为 2 n − 2 2^n-2 2n−2个。抛物线 y a x 2 b x c yax^2bxc yax2bxc与轴…

ST STM32H723ZGTx - NUCLEO-H723ZG DMAMUX_RequestGen例程重现/消化/改进

文章目录 ST STM32H723ZGTx - NUCLEO-H723ZG DMAMUX_RequestGen例程重现/消化/改进概述笔记问题的难点为了确定程序流程, 加入ITM将CubeMX升级到最新将CubeMX说明书翻一下CubeMX配置芯片功能实验工程主要代码.sct文件main.c中断实现文件 stm32h7xx_it.c.ioc补充END ST STM32H72…

探索网络通信核心技术,手写TCPIP用户态协议栈,让性能飙升起来!

一、DPDK简介 DPDK&#xff08;Data Plane Development Kit&#xff09;是一个开源的数据平面开发工具包&#xff0c;它提供了一组C语言库和驱动程序&#xff0c;用于快速开发高性能的数据平面应用程序。DPDK使用用户空间的方式来实现网络数据包处理&#xff0c;从而避免了传统…

海气相互作用 - 全球水循环过程及其量级

全球水循环过程及其量级 单位&#xff1a;Sv106m3/s&#xff0c;大气/陆地/海洋(103 km3)径流1.3 Sv≈台湾暖流1.1 Sv≈白令海峡0.9-1.1 Sv 从涡度平衡的角度说明为什么大洋强化发生在西边界而非东边界 有且只有在大洋西边界强化&#xff0c;才可以使得摩擦力产生一个正的涡…

【线程池】Java线程池的内部类Worker详解

目录 一、简介 二、Worker类对象的类图 三、Worker类对象的解释 4.2 Worker继承自AQS有何意义&#xff1f; 四、Worker的主要代码 4.1 运行worker 4.2 worker和ThreadPool的关系 五、Worker源码分析 5.1 Worker实现接口Runnable&#xff0c;执行run方法 5.2 核心方法…